blob: 09f6e90eaa9d653ecf8c30fc4cc6f630b382c892 [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>
AppaRao Puli37fde6b2019-10-25 16:37:50 +053021#include <ipmid/utils.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070022#include <map>
23#include <random>
24#include <sdbusplus/bus.hpp>
25#include <sdbusplus/bus/match.hpp>
26#include <sdbusplus/server/object.hpp>
27#include <sdbusplus/timer.hpp>
28#include <sstream>
29
AppaRao Puli37fde6b2019-10-25 16:37:50 +053030namespace ipmi
31{
32namespace firmware
33{
34constexpr Cmd cmdGetFwVersionInfo = 0x20;
35} // namespace firmware
36} // namespace ipmi
37
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +053038#ifdef INTEL_PFR_ENABLED
39uint32_t imgLength = 0;
40uint32_t imgType = 0;
41bool block0Mapped = false;
42static constexpr uint32_t perBlock0MagicNum = 0xB6EAFD19;
AppaRao Puli37fde6b2019-10-25 16:37:50 +053043
44static constexpr const char *versionIntf =
45 "xyz.openbmc_project.Software.Version";
46
47enum class FWDeviceIDTag : uint8_t
48{
49 bmcActiveImage = 1,
50 bmcRecoveryImage,
51};
52
53const static boost::container::flat_map<FWDeviceIDTag, const char *>
54 fwVersionIdMap{{FWDeviceIDTag::bmcActiveImage,
55 "/xyz/openbmc_project/software/bmc_active"},
56 {FWDeviceIDTag::bmcRecoveryImage,
57 "/xyz/openbmc_project/software/bmc_recovery"}};
58
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +053059#endif
60
James Feistbeaa2eb2019-08-22 10:59:24 -070061static constexpr const char *secondaryFitImageStartAddr = "22480000";
anil kumar appana31f88872019-08-02 15:16:27 +000062static uint8_t getActiveBootImage(void);
Vernon Mauery52ce6622019-05-22 09:19:46 -070063static void register_netfn_firmware_functions() __attribute__((constructor));
64
65// oem return code for firmware update control
66constexpr ipmi_ret_t IPMI_CC_REQ_INVALID_PHASE = 0xd5;
67constexpr ipmi_ret_t IPMI_CC_USB_ATTACH_FAIL = 0x80;
68
Vernon Mauery52ce6622019-05-22 09:19:46 -070069static constexpr bool DEBUG = false;
70
71static constexpr char FW_UPDATE_SERVER_DBUS_NAME[] =
72 "xyz.openbmc_project.fwupdate1.server";
73
74static constexpr char FW_UPDATE_SERVER_PATH[] =
75 "/xyz/openbmc_project/fwupdate1";
76static constexpr char FW_UPDATE_SERVER_INFO_PATH[] =
77 "/xyz/openbmc_project/fwupdate1/info";
78static constexpr char FW_UPDATE_ACTIVE_INFO_PATH[] =
79 "/xyz/openbmc_project/fwupdate1/info/bmc_active";
80static constexpr char FW_UPDATE_BACKUP_INFO_PATH[] =
81 "/xyz/openbmc_project/fwupdate1/info/bmc_backup";
82
83static constexpr char FW_UPDATE_INTERFACE[] = "xyz.openbmc_project.fwupdate1";
84static constexpr char FW_UPDATE_INFO_INTERFACE[] =
85 "xyz.openbmc_project.fwupdate1.fwinfo";
86static constexpr char FW_UPDATE_SECURITY_INTERFACE[] =
87 "xyz.openbmc_project.fwupdate1.security";
88
89constexpr std::size_t operator""_MB(unsigned long long v)
90{
91 return 1024u * 1024u * v;
92}
93static constexpr int FIRMWARE_BUFFER_MAX_SIZE = 32_MB;
94
95static constexpr char FIRMWARE_BUFFER_FILE[] = "/tmp/fw-download.bin";
96static bool local_download_is_active(void)
97{
98 struct stat sb;
99 if (stat(FIRMWARE_BUFFER_FILE, &sb) < 0)
100 return false;
101 return true;
102}
103
104class fw_update_status_cache
105{
106 public:
107 enum
108 {
109 FW_STATE_INIT = 0,
110 FW_STATE_IDLE,
111 FW_STATE_DOWNLOAD,
112 FW_STATE_VERIFY,
113 FW_STATE_WRITE,
114 FW_STATE_READY,
115 FW_STATE_ERROR = 0x0f,
116 FW_STATE_AC_CYCLE_REQUIRED = 0x83,
117 };
Vernon Mauery52ce6622019-05-22 09:19:46 -0700118 uint8_t state()
119 {
120 if (DEBUG)
121 std::cerr << "fw-state: 0x" << std::hex << (int)_state << '\n';
122 if ((_state == FW_STATE_IDLE || _state == FW_STATE_INIT) &&
123 local_download_is_active())
124 {
125 _state = FW_STATE_DOWNLOAD;
126 _percent = 0;
127 }
128 return _state;
129 }
130 uint8_t percent()
131 {
132 return _percent;
133 }
134 std::string msg()
135 {
136 return _msg;
137 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700138 std::string get_software_obj_path()
139 {
140 return _software_obj_path;
141 }
142 void set_software_obj_path(std::string &obj_path)
143 {
144 _software_obj_path = obj_path;
145 _state = FW_STATE_WRITE;
146 _percent = 0;
147 _match = std::make_shared<sdbusplus::bus::match::match>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700148 *_bus,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700149 sdbusplus::bus::match::rules::propertiesChanged(
150 _software_obj_path,
151 "xyz.openbmc_project.Software.ActivationProgress"),
152 [&](sdbusplus::message::message &msg) {
153 if (DEBUG)
154 std::cerr << "propertiesChanged lambda\n";
155 std::map<std::string, ipmi::DbusVariant> props;
156 std::vector<std::string> inval;
157 std::string iface;
158 msg.read(iface, props, inval);
159 _parse_props(props);
160 });
161 }
162 uint8_t activation_timer_timeout()
163 {
164 std::cerr << "activation_timer_timout(): increase percentage...\n";
165 _percent = _percent + 5;
anil kumar appana31f88872019-08-02 15:16:27 +0000166 if (_percent >= 95)
167 {
168 /*changing the state to ready to update firmware utility */
169 _state = FW_STATE_READY;
170 }
171 std::cerr << " _percent = " << (int)_percent << "\n";
Vernon Mauery52ce6622019-05-22 09:19:46 -0700172 return _percent;
173 }
anil kumar appana31f88872019-08-02 15:16:27 +0000174 /* API for changing state to ERROR */
175 void firmwareUpdateAbortState()
176 {
177 unlink(FIRMWARE_BUFFER_FILE);
178 // changing the state to error
179 _state = FW_STATE_ERROR;
180 }
181 void setDeferRestart(bool deferRestart)
182 {
183 _deferRestart = deferRestart;
184 }
185 void setInhibitDowngrade(bool inhibitDowngrade)
186 {
187 _inhibitDowngrade = inhibitDowngrade;
188 }
189 bool getDeferRestart()
190 {
191 return _deferRestart;
192 }
193 bool getInhibitDowngrade()
194 {
195 return _inhibitDowngrade;
196 }
197
Vernon Mauery52ce6622019-05-22 09:19:46 -0700198 protected:
199 void _parse_props(std::map<std::string, ipmi::DbusVariant> &properties)
200 {
201 if (DEBUG)
202 std::cerr << "propertiesChanged (" << properties.size()
203 << " elements)";
204 for (const auto &t : properties)
205 {
206 auto key = t.first;
207 auto value = t.second;
208 if (key == "state")
209 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700210 auto state = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700211 if (DEBUG)
212 std::cerr << ", state=" << state;
213 if (state == "INIT")
214 _state = FW_STATE_INIT;
215 else if (state == "IDLE")
216 _state = FW_STATE_IDLE;
217 else if (state == "DOWNLOAD")
218 _state = FW_STATE_DOWNLOAD;
219 else if (state == "VERIFY")
220 _state = FW_STATE_VERIFY;
221 else if (state == "WRITE")
222 _state = FW_STATE_WRITE;
223 else if (state == "READY")
224 _state = FW_STATE_READY;
225 else if (state == "ERROR")
226 _state = FW_STATE_ERROR;
227 else if (state == "AC_CYCLE_REQUIRED")
228 _state = FW_STATE_AC_CYCLE_REQUIRED;
229 else
230 {
231 _state = FW_STATE_ERROR;
232 _msg = "internal error";
233 }
234 }
235 else if (key == "percent")
236 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700237 _percent = std::get<int32_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700238 if (DEBUG)
239 std::cerr << ", pct=" << (int)_percent;
240 }
241 else if (key == "msg")
242 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700243 _msg = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700244 if (DEBUG)
245 std::cerr << ", msg='" << _msg << '\'';
246 }
247 else if (key == "Progress")
248 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700249 _percent = std::get<uint8_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700250 ;
251 if (_percent == 100)
252 _state = FW_STATE_READY;
253 }
254 }
255 if ((_state == FW_STATE_IDLE || _state == FW_STATE_INIT) &&
256 local_download_is_active())
257 {
258 _state = FW_STATE_DOWNLOAD;
259 _percent = 0;
260 }
261 if (DEBUG)
262 std::cerr << '\n';
263 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700264
Vernon Mauery15419dd2019-05-24 09:40:30 -0700265 std::shared_ptr<sdbusplus::asio::connection> _bus;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700266 std::shared_ptr<sdbusplus::bus::match::match> _match;
267 uint8_t _state = 0;
268 uint8_t _percent = 0;
anil kumar appana31f88872019-08-02 15:16:27 +0000269 bool _deferRestart = false;
270 bool _inhibitDowngrade = false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700271 std::string _msg;
272
273 private:
274 std::string _software_obj_path;
275};
276
277static fw_update_status_cache fw_update_status;
278
279static std::chrono::steady_clock::time_point fw_random_number_timestamp;
280static constexpr int FW_RANDOM_NUMBER_LENGTH = 8;
281static constexpr auto FW_RANDOM_NUMBER_TTL = std::chrono::seconds(30);
282static uint8_t fw_random_number[FW_RANDOM_NUMBER_LENGTH];
283
284static ipmi_ret_t ipmi_firmware_get_fw_random_number(
285 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
286 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
287{
288 std::random_device rd;
289 std::default_random_engine gen(rd());
290 std::uniform_int_distribution<> dist{0, 255};
291
292 if (*data_len != 0)
293 {
294 *data_len = 0;
295 return IPMI_CC_REQ_DATA_LEN_INVALID;
296 }
297
298 fw_random_number_timestamp = std::chrono::steady_clock::now();
299
300 uint8_t *msg_reply = static_cast<uint8_t *>(response);
301 for (int i = 0; i < FW_RANDOM_NUMBER_LENGTH; i++)
302 fw_random_number[i] = msg_reply[i] = dist(gen);
303
304 if (DEBUG)
305 std::cerr << "FW Rand Num: 0x" << std::hex << (int)msg_reply[0] << " 0x"
306 << (int)msg_reply[1] << " 0x" << (int)msg_reply[2] << " 0x"
307 << (int)msg_reply[3] << " 0x" << (int)msg_reply[4] << " 0x"
308 << (int)msg_reply[5] << " 0x" << (int)msg_reply[6] << " 0x"
309 << (int)msg_reply[7] << '\n';
310
311 *data_len = FW_RANDOM_NUMBER_LENGTH;
312
313 return IPMI_CC_OK;
314}
315
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530316/** @brief Set Firmware Update Mode
317 *
318 * This function sets BMC into firmware update mode
319 * after validating Random number obtained from the Get
320 * Firmware Update Random Number command
321 *
322 * @parameter
323 * - randNum - Random number(token)
324 * @returns IPMI completion code
325 **/
326ipmi::RspType<> ipmiSetFirmwareUpdateMode(
327 std::array<uint8_t, FW_RANDOM_NUMBER_LENGTH> &randNum)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700328{
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530329 /* Firmware Update Random number is valid for 30 seconds only */
330 auto timeElapsed =
331 (std::chrono::steady_clock::now() - fw_random_number_timestamp);
332 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700333 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
334 FW_RANDOM_NUMBER_TTL)
335 .count())
336 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530337 phosphor::logging::log<phosphor::logging::level::INFO>(
338 "Firmware update random number expired.");
339 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700340 }
341
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530342 /* Validate random number */
Vernon Mauery52ce6622019-05-22 09:19:46 -0700343 for (int i = 0; i < FW_RANDOM_NUMBER_LENGTH; i++)
344 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530345 if (fw_random_number[i] != randNum[i])
Vernon Mauery52ce6622019-05-22 09:19:46 -0700346 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530347 phosphor::logging::log<phosphor::logging::level::INFO>(
348 "Invalid random number specified.");
349 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700350 }
351 }
352
353 if (fw_update_status.state() != fw_update_status_cache::FW_STATE_IDLE
354 // TODO: Allowing FW_STATE_INIT here to let image activation available
355 // without being in FW_STATE_IDLE, need to fix/adjust the state machine
356 // to match xyz.openbmc_project.Software.BMC.Updater service activation
357 // mechanism at finer grain
358 && fw_update_status.state() != fw_update_status_cache::FW_STATE_INIT)
359 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530360 phosphor::logging::log<phosphor::logging::level::INFO>(
361 "Already firmware update is in progress.");
362 return ipmi::responseBusy();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700363 }
364 // FIXME? c++ doesn't off an option for exclusive file creation
365 FILE *fp = fopen(FIRMWARE_BUFFER_FILE, "wx");
366 if (!fp)
367 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530368 phosphor::logging::log<phosphor::logging::level::INFO>(
369 "Unable to open file.");
370 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700371 }
372 fclose(fp);
373
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530374 return ipmi::responseSuccess();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700375}
376
anil kumar appanab57098a2019-05-28 16:22:33 +0000377/** @brief implements exit firmware update mode command
378 * @param None
379 *
380 * @returns IPMI completion code
381 */
382ipmi::RspType<> ipmiFirmwareExitFwUpdateMode()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700383{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700384
anil kumar appanab57098a2019-05-28 16:22:33 +0000385 if (DEBUG)
386 {
387 std::cerr << "Exit FW update mode \n";
388 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700389 switch (fw_update_status.state())
390 {
391 case fw_update_status_cache::FW_STATE_INIT:
392 case fw_update_status_cache::FW_STATE_IDLE:
anil kumar appanab57098a2019-05-28 16:22:33 +0000393 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700394 break;
395 case fw_update_status_cache::FW_STATE_DOWNLOAD:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700396 case fw_update_status_cache::FW_STATE_VERIFY:
397 break;
398 case fw_update_status_cache::FW_STATE_WRITE:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700399 break;
400 case fw_update_status_cache::FW_STATE_READY:
401 case fw_update_status_cache::FW_STATE_ERROR:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700402 break;
403 case fw_update_status_cache::FW_STATE_AC_CYCLE_REQUIRED:
anil kumar appanab57098a2019-05-28 16:22:33 +0000404 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700405 break;
406 }
anil kumar appanab57098a2019-05-28 16:22:33 +0000407 fw_update_status.firmwareUpdateAbortState();
408 return ipmi::responseSuccess();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700409}
410
411static void post_transfer_complete_handler(
412 std::unique_ptr<sdbusplus::bus::match::match> &fw_update_matcher);
413static bool request_start_firmware_update(const std::string &uri)
414{
415 if (DEBUG)
416 std::cerr << "request start firmware update()\n";
417
Vernon Mauery52ce6622019-05-22 09:19:46 -0700418 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
419 // the code gets to this point, the file should be transferred start the
420 // request (creating a new file in /tmp/images causes the update manager to
421 // check if it is ready for activation)
422 static std::unique_ptr<sdbusplus::bus::match::match> fw_update_matcher;
423 post_transfer_complete_handler(fw_update_matcher);
424 std::filesystem::rename(
425 uri, "/tmp/images/" +
426 boost::uuids::to_string(boost::uuids::random_generator()()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700427 return true;
428}
429
430class transfer_hash_check
431{
432 public:
433 enum hash_check
434 {
435 CHECK_NOT_REQUESTED = 0,
436 CHECK_REQUESTED,
437 CHECK_PASSED_SHA2,
438 CHECK_RESVD1,
439 CHECK_FAILED_SHA2 = 0xe2,
440 CHECK_RESVD2 = 0xe3,
441 };
442
443 protected:
444 EVP_MD_CTX *_ctx;
445 std::vector<uint8_t> _expected;
446 enum hash_check _check;
447 bool _started;
448
449 public:
450 transfer_hash_check() : _check(CHECK_NOT_REQUESTED), _started(false)
451 {
452 }
453 ~transfer_hash_check()
454 {
455 if (_ctx)
456 {
457 EVP_MD_CTX_destroy(_ctx);
458 _ctx = NULL;
459 }
460 }
461 void init(const std::vector<uint8_t> &expected)
462 {
463 _expected = expected;
464 _check = CHECK_REQUESTED;
465 _ctx = EVP_MD_CTX_create();
466 EVP_DigestInit(_ctx, EVP_sha256());
467 }
468 void hash(const std::vector<uint8_t> &data)
469 {
470 if (!_started)
471 _started = true;
472 EVP_DigestUpdate(_ctx, data.data(), data.size());
473 }
474 void clear()
475 {
476 // if not started, nothing to clear
477 if (_started)
478 {
479 if (_ctx)
480 EVP_MD_CTX_destroy(_ctx);
481 if (_check != CHECK_NOT_REQUESTED)
482 _check = CHECK_REQUESTED;
483 _ctx = EVP_MD_CTX_create();
484 EVP_DigestInit(_ctx, EVP_sha256());
485 }
486 }
487 enum hash_check check()
488 {
489 if (_check == CHECK_REQUESTED)
490 {
491 unsigned int len;
492 std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
493 EVP_DigestFinal(_ctx, digest.data(), &len);
494 if (digest == _expected)
495 {
496 if (DEBUG)
497 std::cerr << "transfer sha2 check passed\n";
498 _check = CHECK_PASSED_SHA2;
499 }
500 else
501 {
502 if (DEBUG)
503 std::cerr << "transfer sha2 check failed\n";
504 _check = CHECK_FAILED_SHA2;
505 }
506 }
507 return _check;
508 }
509 uint8_t status() const
510 {
511 return static_cast<uint8_t>(_check);
512 }
513};
514
515std::shared_ptr<transfer_hash_check> xfer_hash_check;
516
Vernon Mauery52ce6622019-05-22 09:19:46 -0700517static void activate_image(const char *obj_path)
518{
anil kumar appana31f88872019-08-02 15:16:27 +0000519 // If flag is false means to reboot
520 if (fw_update_status.getDeferRestart() == false)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700521 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700522
anil kumar appana31f88872019-08-02 15:16:27 +0000523 if (DEBUG)
524 {
525 std::cerr << "activateImage()...\n";
526 std::cerr << "obj_path = " << obj_path << "\n";
527 }
528 phosphor::logging::log<phosphor::logging::level::INFO>(
529 "activating Image: ",
530 phosphor::logging::entry("OBJPATH =%s", obj_path));
531 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
532 bus->async_method_call(
533 [](const boost::system::error_code ec) {
534 if (ec)
535 {
536 phosphor::logging::log<phosphor::logging::level::ERR>(
537 "async_method_call error: activate_image failed");
538 return;
539 }
540 },
541 "xyz.openbmc_project.Software.BMC.Updater", obj_path,
542 "org.freedesktop.DBus.Properties", "Set",
543 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
544 std::variant<std::string>("xyz.openbmc_project.Software.Activation."
545 "RequestedActivations.Active"));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700546 }
anil kumar appana31f88872019-08-02 15:16:27 +0000547 else
Vernon Mauery52ce6622019-05-22 09:19:46 -0700548 {
anil kumar appana31f88872019-08-02 15:16:27 +0000549 phosphor::logging::log<phosphor::logging::level::INFO>(
550 "Firmware image activation is deferred.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700551 }
552}
553
554static void post_transfer_complete_handler(
555 std::unique_ptr<sdbusplus::bus::match::match> &fw_update_matcher)
556{
557 // Setup timer for watching signal
558 static phosphor::Timer timer(
559 [&fw_update_matcher]() { fw_update_matcher = nullptr; });
560
561 static phosphor::Timer activation_status_timer([]() {
562 if (fw_update_status.activation_timer_timeout() >= 95)
563 {
564 activation_status_timer.stop();
565 }
566 });
567
568 timer.start(std::chrono::microseconds(5000000), false);
569
570 // callback function for capturing signal
571 auto callback = [&fw_update_matcher](sdbusplus::message::message &m) {
572 if (DEBUG)
573 std::cerr << "[complete] Match fired\n";
574 bool flag = false;
575
576 std::vector<std::pair<
577 std::string,
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700578 std::vector<std::pair<std::string, std::variant<std::string>>>>>
Vernon Mauery52ce6622019-05-22 09:19:46 -0700579 interfaces_properties;
580
581 sdbusplus::message::object_path obj_path;
582
583 try
584 {
585 m.read(obj_path, interfaces_properties); // Read in the object path
586 // that was just created
587 }
588 catch (std::exception &e)
589 {
590 std::cerr
591 << "[complete] Failed at post_transfer_complete-handler : "
592 << e.what() << "\n";
593 }
594 // constructing response message
595 if (DEBUG)
596 std::cerr << "[complete] obj path = " << obj_path.str << "\n";
597 for (auto &interface : interfaces_properties)
598 {
599 if (DEBUG)
600 std::cerr << "[complete] interface = " << interface.first
601 << "\n";
602
603 if (interface.first == "xyz.openbmc_project.Software.Activation")
604 {
605 // cancel timer only when
606 // xyz.openbmc_project.Software.Activation interface is
607 // added
608
609 if (DEBUG)
610 std::cerr << "[complete] Attempt to cancel timer...\n";
611 try
612 {
613 timer.stop();
614 activation_status_timer.start(
615 std::chrono::microseconds(3000000), true);
616 }
617 catch (std::exception &e)
618 {
619 std::cerr << "[complete] cancel timer error: " << e.what()
620 << "\n";
621 }
622
623 fw_update_status.set_software_obj_path(obj_path.str);
624 activate_image(obj_path.str.c_str());
625 if (DEBUG)
626 std::cerr << "[complete] returned from activeImage()\n";
627
628 fw_update_matcher = nullptr;
629 }
630 }
631 };
632
633 // Adding matcher
634 fw_update_matcher = std::make_unique<sdbusplus::bus::match::match>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700635 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700636 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
637 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
638 callback);
639}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700640
641class MappedFile
642{
643 public:
644 MappedFile(const std::string &fname) : addr(nullptr), fsize(0)
645 {
646 std::error_code ec;
647 size_t sz = std::filesystem::file_size(fname, ec);
648 int fd = open(fname.c_str(), O_RDONLY);
649 if (!ec || fd < 0)
650 {
651 return;
652 }
653 void *tmp = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
654 close(fd);
655 if (tmp == MAP_FAILED)
656 {
657 return;
658 }
659 addr = tmp;
660 fsize = sz;
661 }
662
663 ~MappedFile()
664 {
665 if (addr)
666 {
667 munmap(addr, fsize);
668 }
669 }
670 const uint8_t *data() const
671 {
672 return static_cast<const uint8_t *>(addr);
673 }
674 size_t size() const
675 {
676 return fsize;
677 }
678
679 private:
680 size_t fsize;
681 void *addr;
682};
683
684static int transfer_from_file(const std::string &uri, bool move = true)
685{
686 std::error_code ec;
687 if (DEBUG)
688 std::cerr << "transfer_from_file(" << uri << ")\n";
689 if (move)
690 {
691 std::filesystem::rename(uri, FIRMWARE_BUFFER_FILE, ec);
692 }
693 else
694 {
695 std::filesystem::copy(uri, FIRMWARE_BUFFER_FILE,
696 std::filesystem::copy_options::overwrite_existing,
697 ec);
698 }
699 if (xfer_hash_check)
700 {
701 MappedFile mappedfw(uri);
702 xfer_hash_check->hash(
703 {mappedfw.data(), mappedfw.data() + mappedfw.size()});
704 }
705 if (ec.value())
706 {
707 std::cerr << "cp/mv returns: " << ec.message() << "(" << ec.value()
708 << ")\n";
709 }
710 return ec.value();
711}
712
713template <typename... ArgTypes>
714static int executeCmd(const char *path, ArgTypes &&... tArgs)
715{
716 boost::process::child execProg(path, const_cast<char *>(tArgs)...);
717 execProg.wait();
718 return execProg.exit_code();
719}
720
721constexpr char USB_CTRL_PATH[] = "/usr/bin/usb-ctrl";
722constexpr char FWUPDATE_MOUNT_POINT[] = "/tmp/usb-fwupd.mnt";
723constexpr char FWUPDATE_USB_VOL_IMG[] = "/tmp/usb-fwupd.img";
724constexpr char FWUPDATE_USB_DEV_NAME[] = "fw-usb-mass-storage-dev";
725constexpr size_t fwPathMaxLength = 255;
726static int transfer_from_usb(const std::string &uri)
727{
728 int ret, sysret;
729 char fwpath[fwPathMaxLength];
730 if (DEBUG)
731 std::cerr << "transfer_from_usb(" << uri << ")\n";
732 ret = executeCmd(USB_CTRL_PATH, "mount", FWUPDATE_USB_VOL_IMG,
733 FWUPDATE_MOUNT_POINT);
734 if (ret)
735 {
736 return ret;
737 }
738
739 std::string usb_path = std::string(FWUPDATE_MOUNT_POINT) + "/" + uri;
740 ret = transfer_from_file(usb_path, false);
741
742 executeCmd(USB_CTRL_PATH, "cleanup", FWUPDATE_USB_VOL_IMG,
743 FWUPDATE_MOUNT_POINT);
744 return ret;
745}
746
747static bool transfer_firmware_from_uri(const std::string &uri)
748{
749 static constexpr char FW_URI_FILE[] = "file://";
750 static constexpr char FW_URI_USB[] = "usb://";
751 if (DEBUG)
752 std::cerr << "transfer_firmware_from_uri(" << uri << ")\n";
753 if (boost::algorithm::starts_with(uri, FW_URI_FILE))
754 {
755 std::string fname = uri.substr(sizeof(FW_URI_FILE) - 1);
756 if (fname != FIRMWARE_BUFFER_FILE)
757 {
758 return 0 == transfer_from_file(fname);
759 }
760 return true;
761 }
762 if (boost::algorithm::starts_with(uri, FW_URI_USB))
763 {
764 std::string fname = uri.substr(sizeof(FW_URI_USB) - 1);
765 return 0 == transfer_from_usb(fname);
766 }
767 return false;
768}
769
770/* Get USB-mass-storage device status: inserted => true, ejected => false */
771static int usb_get_status()
772{
773 static constexpr char usb_gadget_base[] = "/sys/kernel/config/usb_gadget/";
774 auto usb_device =
775 std::filesystem::path(usb_gadget_base) / FWUPDATE_USB_DEV_NAME;
776 std::error_code ec;
777 return std::filesystem::exists(usb_device, ec) && !ec;
778}
779
780/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
781static int usb_attach_device()
782{
783 if (usb_get_status())
784 {
785 return 1;
786 }
787 int ret =
788 executeCmd(USB_CTRL_PATH, "setup", FWUPDATE_USB_VOL_IMG,
789 std::to_string(FIRMWARE_BUFFER_MAX_SIZE / 1_MB).c_str());
790 if (!ret)
791 {
792 ret = executeCmd(USB_CTRL_PATH, "insert", FWUPDATE_USB_DEV_NAME,
793 FWUPDATE_USB_VOL_IMG);
794 }
795 return ret;
796}
797
798/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
799static int usb_detach_device()
800{
801 if (!usb_get_status())
802 {
803 return 1;
804 }
805 return executeCmd(USB_CTRL_PATH, "eject", FWUPDATE_USB_DEV_NAME);
806}
807
808constexpr uint8_t controls_init = 0x00;
809constexpr uint8_t controls_transfer_started = 0x01;
810constexpr uint8_t controls_transfer_completed = 0x02;
811constexpr uint8_t controls_transfer_aborted = 0x04;
812constexpr uint8_t controls_usb_attached = 0x08;
813
814struct fw_update_control_request
815{
816 enum knob
817 {
818 CTRL_GET = 0,
819 CTRL_XFER_START,
820 CTRL_XFER_COMPLETE,
821 CTRL_XFER_ABORT,
822 CTRL_SET_FILENAME,
823 CTRL_USB_ATTACH,
824 CTRL_USB_DETACH,
825 } __attribute__((packed));
826 enum knob control;
827 uint8_t nlen;
828 char filename[fwPathMaxLength];
829} __attribute__((packed));
830
831static ipmi_ret_t ipmi_firmware_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
832 ipmi_request_t request,
833 ipmi_response_t response,
834 ipmi_data_len_t data_len,
835 ipmi_context_t context)
836{
837 static std::string fw_xfer_uri;
838
839 if (DEBUG)
840 std::cerr << "FW update control\n";
841 *data_len = 0;
842
843 static uint8_t controls = controls_init;
844 ipmi_ret_t rc = IPMI_CC_OK;
845 auto ctrl_req = reinterpret_cast<fw_update_control_request *>(request);
846 auto ctrl_resp = reinterpret_cast<uint8_t *>(response);
847
848 if (usb_get_status())
849 {
850 controls |= controls_usb_attached;
851 }
852 else
853 {
854 controls &= ~controls_usb_attached;
855 }
856
857 switch (ctrl_req->control)
858 {
859 case fw_update_control_request::CTRL_GET:
860 break;
861 case fw_update_control_request::CTRL_XFER_START:
862 {
863 controls |= controls_transfer_started;
864 // reset buffer to empty (truncate file)
865 std::ofstream out(FIRMWARE_BUFFER_FILE,
866 std::ofstream::binary | std::ofstream::trunc);
867 fw_xfer_uri = std::string("file://") + FIRMWARE_BUFFER_FILE;
868 if (xfer_hash_check)
869 {
870 xfer_hash_check->clear();
871 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +0530872#ifdef INTEL_PFR_ENABLED
873 imgLength = 0;
874 imgType = 0;
875 block0Mapped = false;
876#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -0700877 if (DEBUG)
878 std::cerr << "transfer start\n";
879 }
880 break;
881 case fw_update_control_request::CTRL_XFER_COMPLETE:
882 {
883 if (usb_get_status())
884 {
885 rc = IPMI_CC_REQ_INVALID_PHASE;
886 }
887 // finish transfer based on URI
888 if (!transfer_firmware_from_uri(fw_xfer_uri))
889 {
890 rc = IPMI_CC_UNSPECIFIED_ERROR;
891 break;
892 }
893 // transfer complete
894 if (xfer_hash_check)
895 {
896 if (transfer_hash_check::CHECK_PASSED_SHA2 !=
897 xfer_hash_check->check())
898 {
899 if (DEBUG)
900 std::cerr << "xfer_hash_check returns not "
901 "CHECK_PASSED_SHA2\n";
902 rc = IPMI_CC_UNSPECIFIED_ERROR;
903 break;
904 }
905 }
906 // start the request
907 if (!request_start_firmware_update(FIRMWARE_BUFFER_FILE))
908 {
909 if (DEBUG)
910 std::cerr
911 << "request_start_firmware_update returns failure\n";
912 rc = IPMI_CC_UNSPECIFIED_ERROR;
913 }
914 if (rc == IPMI_CC_OK)
915 {
916 controls |= controls_transfer_completed;
917 }
918 }
919 break;
920 case fw_update_control_request::CTRL_XFER_ABORT:
921 if (DEBUG)
922 std::cerr << "send abort request\n";
923 if (usb_get_status())
924 {
925 if (0 != usb_detach_device())
926 {
927 rc = IPMI_CC_USB_ATTACH_FAIL;
928 }
929 }
anil kumar appana31f88872019-08-02 15:16:27 +0000930 fw_update_status.firmwareUpdateAbortState();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700931 controls |= controls_transfer_aborted;
932 break;
933 case fw_update_control_request::CTRL_SET_FILENAME:
934 fw_xfer_uri.clear();
935 fw_xfer_uri.insert(0, ctrl_req->filename, ctrl_req->nlen);
936 break;
937 case fw_update_control_request::CTRL_USB_ATTACH:
938 if (usb_get_status())
939 {
940 rc = IPMI_CC_INVALID_FIELD_REQUEST;
941 }
942 else if (0 != usb_attach_device())
943 {
944 rc = IPMI_CC_USB_ATTACH_FAIL;
945 }
946 else
947 {
948 rc = IPMI_CC_OK;
949 }
950 break;
951 case fw_update_control_request::CTRL_USB_DETACH:
952 if (!usb_get_status())
953 {
954 rc = IPMI_CC_INVALID_FIELD_REQUEST;
955 }
956 if (0 != usb_detach_device())
957 {
958 rc = IPMI_CC_USB_ATTACH_FAIL;
959 }
960 else
961 {
962 rc = IPMI_CC_OK;
963 }
964 break;
965 default:
966 if (DEBUG)
967 std::cerr << "control byte " << std::hex << ctrl_req->control
968 << " unknown\n";
969 rc = IPMI_CC_INVALID_FIELD_REQUEST;
970 break;
971 }
972
973 if (rc == IPMI_CC_OK)
974 {
975 *ctrl_resp = controls;
976 *data_len = sizeof(*ctrl_resp);
977 }
978
979 return rc;
980}
981
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530982#ifdef INTEL_PFR_ENABLED
983using fwVersionInfoType = std::tuple<uint8_t, // ID Tag
984 uint8_t, // Major Version Number
985 uint8_t, // Minor Version Number
986 uint32_t, // Build Number
987 uint32_t, // Build Timestamp
988 uint32_t>; // Update Timestamp
989ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700990{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700991 // Byte 1 - Count (N) Number of devices data is being returned for.
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530992 // Bytes 2:16 - Device firmare information(fwVersionInfoType)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700993 // Bytes - 17:(15xN) - Repeat of 2 through 16
994
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530995 std::vector<fwVersionInfoType> fwVerInfoList;
996 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
997 for (const auto &fwDev : fwVersionIdMap)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700998 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530999 std::string verStr;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001000 try
1001 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301002 auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001003
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301004 ipmi::Value result = ipmi::getDbusProperty(
1005 *busp, service, fwDev.second, versionIntf, "Version");
1006 verStr = std::get<std::string>(result);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001007 }
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301008 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001009 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301010 phosphor::logging::log<phosphor::logging::level::INFO>(
1011 "Failed to fetch Version property",
1012 phosphor::logging::entry("ERROR=%s", e.what()),
1013 phosphor::logging::entry("PATH=%s", fwDev.second),
1014 phosphor::logging::entry("INTERFACE=%s", versionIntf));
1015 continue;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001016 }
1017
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301018 if (verStr.empty())
1019 {
1020 phosphor::logging::log<phosphor::logging::level::INFO>(
1021 "Version is empty.",
1022 phosphor::logging::entry("PATH=%s", fwDev.second),
1023 phosphor::logging::entry("INTERFACE=%s", versionIntf));
1024 continue;
1025 }
1026
1027 // BMC Version format: <major>.<minor>-<build bum>-<build hash>
1028 std::vector<std::string> splitVer;
1029 boost::split(splitVer, verStr, boost::is_any_of(".-"));
1030 if (splitVer.size() < 3)
1031 {
1032 phosphor::logging::log<phosphor::logging::level::INFO>(
1033 "Invalid Version format.",
1034 phosphor::logging::entry("Version=%s", verStr.c_str()),
1035 phosphor::logging::entry("PATH=%s", fwDev.second));
1036 continue;
1037 }
1038
1039 uint8_t majorNum = 0;
1040 uint8_t minorNum = 0;
1041 uint32_t buildNum = 0;
1042 try
1043 {
1044 majorNum = std::stoul(splitVer[0], nullptr, 16);
1045 minorNum = std::stoul(splitVer[1], nullptr, 16);
1046 buildNum = std::stoul(splitVer[2], nullptr, 16);
1047 }
1048 catch (const std::exception &e)
1049 {
1050 phosphor::logging::log<phosphor::logging::level::INFO>(
1051 "Failed to convert stoul.",
1052 phosphor::logging::entry("ERROR=%s", e.what()));
1053 continue;
1054 }
1055
1056 // Build Timestamp - Not supported.
1057 // Update Timestamp - TODO: Need to check with CPLD team.
1058 fwVerInfoList.emplace_back(
1059 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
1060 minorNum, buildNum, 0, 0));
Vernon Mauery52ce6622019-05-22 09:19:46 -07001061 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001062
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301063 return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001064}
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301065#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001066
1067struct fw_security_revision_info
1068{
1069 uint8_t id_tag;
1070 uint16_t sec_rev;
1071} __attribute__((packed));
1072
1073static ipmi_ret_t ipmi_firmware_get_fw_security_revision(
1074 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1075 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1076{
1077 if (DEBUG)
1078 std::cerr << "Get FW security revision info\n";
1079
1080 // Byte 1 - Count (N) Number of devices data is being returned for.
1081 // Byte 2 - ID Tag 00 – reserved 01 – BMC Active Image 02 – BBU Active Image
1082 // 03 – BMC Backup Image 04 – BBU Backup Image 05 – BBR
1083 // Image
1084 // Byte 3 - Major Version Number
1085 // Byte 4 - Minor Version Number
1086 // Bytes 5:8 - Build Number
1087 // Bytes 9:12 - Build Timestamp Format: LSB first, same format as SEL
1088 // timestamp
1089 // Bytes 13:16 - Update Timestamp
1090 // Bytes - 17:(15xN) - Repeat of 2 through 16
1091
1092 uint8_t count = 0;
1093 auto ret_count = reinterpret_cast<uint8_t *>(response);
1094 auto info =
1095 reinterpret_cast<struct fw_security_revision_info *>(ret_count + 1);
1096
Vernon Mauery15419dd2019-05-24 09:40:30 -07001097 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001098 for (uint8_t id_tag = 1; id_tag < 6; id_tag++)
1099 {
1100 const char *fw_path;
1101 switch (id_tag)
1102 {
1103 case 1:
1104 fw_path = FW_UPDATE_ACTIVE_INFO_PATH;
1105 break;
1106 case 2:
1107 fw_path = FW_UPDATE_BACKUP_INFO_PATH;
1108 break;
1109 case 3:
1110 case 4:
1111 case 5:
1112 continue; // skip for now
1113 break;
1114 }
1115 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001116 bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, fw_path,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001117 "org.freedesktop.DBus.Properties", "GetAll");
1118 method.append(FW_UPDATE_INFO_INTERFACE, "security_version");
1119 ipmi::DbusVariant sec_rev;
1120 try
1121 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001122 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001123
1124 if (reply.is_method_error())
1125 continue;
1126
1127 reply.read(sec_rev);
1128 }
1129 catch (sdbusplus::exception::SdBusError &e)
1130 {
1131 std::cerr << "SDBus Error: " << e.what();
1132 return IPMI_CC_UNSPECIFIED_ERROR;
1133 }
1134
1135 info->id_tag = id_tag;
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001136 info->sec_rev = std::get<int>(sec_rev);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001137 count++;
1138 info++;
1139 }
1140 *ret_count = count;
1141
1142 // Status code.
1143 ipmi_ret_t rc = IPMI_CC_OK;
1144 *data_len = sizeof(count) + count * sizeof(*info);
1145
1146 return rc;
1147}
1148
1149struct fw_channel_size
1150{
1151 uint8_t channel_id;
1152 uint32_t channel_size;
1153} __attribute__((packed));
1154
1155enum
1156{
1157 CHANNEL_RESVD = 0,
1158 CHANNEL_KCS,
1159 CHANNEL_RMCP_PLUS,
1160 CHANNEL_USB_DATA,
1161 CHANNEL_USB_MASS_STORAGE,
1162} channel_transfer_type;
1163
anil kumar appana159547c2019-05-31 16:08:34 +00001164static constexpr uint8_t channelListSize = 2;
1165/** @brief implements Maximum Firmware Transfer size command
1166 * @parameter
1167 * - none
1168 * @returns IPMI completion code plus response data
1169 * - count - channel count
1170 * - channelList - channel list information
1171 */
1172ipmi::RspType<uint8_t, // channel count
1173 std::array<std::tuple<uint8_t, uint32_t>,
1174 channelListSize> // channel
1175 // list
1176 >
1177 ipmiFirmwareMaxTransferSize()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001178{
anil kumar appana159547c2019-05-31 16:08:34 +00001179 constexpr uint8_t KCSMaxBufSize = 128;
1180 constexpr uint32_t RMCPPLUSMaxBufSize = 50 * 1024;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001181 if (DEBUG)
1182 std::cerr << "Get FW max transfer size\n";
Vernon Mauery52ce6622019-05-22 09:19:46 -07001183 // Byte 1 - Count (N) Number of devices data is being returned for.
1184 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+,
1185 // 03 – usb data, 04 – usb mass storage
1186 // Byte 3-6 - transfer size (little endian)
1187 // Bytes - 7:(5xN) - Repeat of 2 through 6
anil kumar appana159547c2019-05-31 16:08:34 +00001188 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
1189 channelList = {{{CHANNEL_KCS, KCSMaxBufSize},
1190 {CHANNEL_RMCP_PLUS, RMCPPLUSMaxBufSize}}};
1191 return ipmi::responseSuccess(channelListSize, channelList);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001192}
1193
1194enum
1195{
1196 EXEC_CTX_RESVD = 0,
1197 EXEC_CTX_FULL_LINUX = 0x10,
1198 EXEC_CTX_SAFE_MODE_LINUX = 0x11,
1199} bmc_execution_context;
1200
1201struct fw_execution_context
1202{
1203 uint8_t context;
1204 uint8_t image_selection;
1205} __attribute__((packed));
1206
1207static ipmi_ret_t ipmi_firmware_get_fw_execution_context(
1208 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1209 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1210{
1211 if (DEBUG)
1212 std::cerr << "Get FW execution context\n";
1213
1214 // Byte 1 - execution context
1215 // 0x10 - full linux stack, 0x11 - safe-mode linux stack
1216 // Byte 2 - current image selection
1217 // 1 - primary, 2 - secondary
1218
1219 auto info = reinterpret_cast<struct fw_execution_context *>(response);
anil kumar appana31f88872019-08-02 15:16:27 +00001220 info->context = EXEC_CTX_FULL_LINUX;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001221
anil kumar appana31f88872019-08-02 15:16:27 +00001222 info->image_selection = getActiveBootImage();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001223
1224 // Status code.
1225 ipmi_ret_t rc = IPMI_CC_OK;
1226 *data_len = sizeof(*info);
1227
1228 return rc;
1229}
1230
anil kumar appana31f88872019-08-02 15:16:27 +00001231uint8_t getActiveBootImage(void)
1232{
1233 // 0x01 - primaryImage
1234 constexpr uint8_t primaryImage = 0x01;
1235 // 0x02 - secondaryImage
1236 constexpr uint8_t secondaryImage = 0x02;
1237 uint8_t bootImage = primaryImage;
1238
1239 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1240 auto method = bus->new_method_call(
1241 "xyz.openbmc_project.U_Boot.Environment.Manager",
1242 "/xyz/openbmc_project/u_boot/environment/mgr",
1243 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read");
1244 method.append("bootcmd");
1245 std::string value;
1246 try
1247 {
1248 auto reply = bus->call(method);
1249 reply.read(value);
1250 }
1251 catch (sdbusplus::exception::SdBusError &e)
1252 {
1253 std::cerr << "SDBus Error: " << e.what();
1254 return IPMI_CC_UNSPECIFIED_ERROR;
1255 }
1256 /* cheking for secondary FitImage Address 22480000 */
1257 if (value.find(secondaryFitImageStartAddr) != std::string::npos)
1258 {
1259 bootImage = secondaryImage;
1260 }
1261 else
1262 {
1263 bootImage = primaryImage;
1264 }
1265
1266 return bootImage;
1267}
anil kumar appana6c7d9382019-05-31 14:33:13 +00001268/** @brief implements firmware get status command
1269 * @parameter
1270 * - none
1271 * @returns IPMI completion code plus response data
1272 * - status - processing status
1273 * - percentage - percentage completion
1274 * - check - channel integrity check status
1275 **/
1276ipmi::RspType<uint8_t, // status
1277 uint8_t, // percentage
1278 uint8_t // check
1279 >
1280 ipmiFrmwareGetStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001281
Vernon Mauery52ce6622019-05-22 09:19:46 -07001282{
1283 if (DEBUG)
1284 std::cerr << "Get FW update status\n";
Vernon Mauery52ce6622019-05-22 09:19:46 -07001285 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1286 // 5=ready, f=error, 83=ac cycle required)
1287 // Byte 2 - percent
1288 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
anil kumar appana6c7d9382019-05-31 14:33:13 +00001289 uint8_t status = fw_update_status.state();
1290 uint8_t percent = fw_update_status.percent();
1291 uint8_t check = xfer_hash_check ? xfer_hash_check->status() : 0;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001292
1293 // Status code.
anil kumar appana6c7d9382019-05-31 14:33:13 +00001294 return ipmi::responseSuccess(status, percent, check);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001295}
1296
1297static constexpr uint8_t FW_UPDATE_OPTIONS_NO_DOWNREV = (1 << 0);
1298static constexpr uint8_t FW_UPDATE_OPTIONS_DEFER_RESTART = (1 << 1);
1299static constexpr uint8_t FW_UPDATE_OPTIONS_SHA2_CHECK = (1 << 2);
1300static constexpr uint8_t FW_UPDATE_OPTIONS_RESVD1 = (1 << 3);
1301struct fw_update_options_request
1302{
1303 uint8_t mask;
1304 uint8_t options;
1305} __attribute__((packed));
1306
Vernon Mauery52ce6622019-05-22 09:19:46 -07001307uint32_t fw_update_options = 0;
1308static ipmi_ret_t ipmi_firmware_update_options(
1309 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1310 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1311{
1312 if (DEBUG)
1313 std::cerr << "Get/set FW update options\n";
1314
1315 // request:
1316 // Byte 1 - mask
1317 // Byte 2 - options
1318 // Byte 3-34 - optional integrity check expected value
1319 // response:
1320 // Byte 1 - set options
1321
1322 auto fw_options =
1323 reinterpret_cast<struct fw_update_options_request *>(request);
1324
1325 const char *path = FW_UPDATE_SERVER_INFO_PATH;
1326 const char *iface = FW_UPDATE_SECURITY_INTERFACE;
1327 if ((fw_options->mask & FW_UPDATE_OPTIONS_NO_DOWNREV) &&
1328 (fw_options->options & FW_UPDATE_OPTIONS_NO_DOWNREV) !=
1329 (fw_update_options & FW_UPDATE_OPTIONS_NO_DOWNREV))
1330 {
1331 if (fw_options->options & FW_UPDATE_OPTIONS_NO_DOWNREV)
1332 {
1333 fw_update_options |= FW_UPDATE_OPTIONS_NO_DOWNREV;
anil kumar appana31f88872019-08-02 15:16:27 +00001334 /*setting flag to flase for deferring downgrade support*/
1335 fw_update_status.setInhibitDowngrade(true);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001336 }
1337 else
1338 {
1339 fw_update_options &= ~FW_UPDATE_OPTIONS_NO_DOWNREV;
anil kumar appana31f88872019-08-02 15:16:27 +00001340 /*setting flag to true for downgrade support*/
1341 fw_update_status.setInhibitDowngrade(false);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001342 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001343 }
1344 if ((fw_options->mask & FW_UPDATE_OPTIONS_DEFER_RESTART) &&
1345 (fw_options->options & FW_UPDATE_OPTIONS_DEFER_RESTART) !=
1346 (fw_update_options & FW_UPDATE_OPTIONS_DEFER_RESTART))
1347 {
1348 if (fw_options->options & FW_UPDATE_OPTIONS_DEFER_RESTART)
1349 {
1350 fw_update_options |= FW_UPDATE_OPTIONS_DEFER_RESTART;
anil kumar appana31f88872019-08-02 15:16:27 +00001351 /* setting flag to true to stop image activation */
1352 fw_update_status.setDeferRestart(true);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001353 }
1354 else
1355 {
anil kumar appana31f88872019-08-02 15:16:27 +00001356 /* setting flag to false for image activation */
Vernon Mauery52ce6622019-05-22 09:19:46 -07001357 fw_update_options &= ~FW_UPDATE_OPTIONS_DEFER_RESTART;
anil kumar appana31f88872019-08-02 15:16:27 +00001358 fw_update_status.setDeferRestart(false);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001359 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001360 }
1361 if (fw_options->mask & FW_UPDATE_OPTIONS_SHA2_CHECK)
1362 {
1363 auto hash_size = EVP_MD_size(EVP_sha256());
1364 if (fw_options->options & FW_UPDATE_OPTIONS_SHA2_CHECK)
1365 {
1366 if (*data_len != (sizeof(*fw_options) + hash_size))
1367 {
1368 *data_len = 0;
1369 return IPMI_CC_REQ_DATA_LEN_INVALID;
1370 }
1371 xfer_hash_check = std::make_shared<transfer_hash_check>();
1372 auto exp_hash = reinterpret_cast<uint8_t *>(fw_options + 1);
1373 xfer_hash_check->init({exp_hash, exp_hash + hash_size});
1374 fw_update_options |= FW_UPDATE_OPTIONS_SHA2_CHECK;
1375 }
1376 else
1377 {
1378 fw_update_options &= ~FW_UPDATE_OPTIONS_SHA2_CHECK;
1379 // delete the xfer_hash_check object
1380 xfer_hash_check.reset();
1381 }
1382 }
1383 auto options_rsp = reinterpret_cast<uint8_t *>(response);
1384 *options_rsp = fw_update_options;
1385
1386 if (DEBUG)
1387 std::cerr << "current fw_update_options = " << std::hex
1388 << fw_update_options << '\n';
1389 // Status code.
1390 *data_len = sizeof(*options_rsp);
1391 return IPMI_CC_OK;
1392}
1393
1394struct fw_cert_info
1395{
1396 uint16_t cert_len;
1397 uint64_t serial;
1398 uint8_t subject_len;
1399 char subject[255];
1400} __attribute__((packed));
1401
1402static ipmi_ret_t ipmi_firmware_get_root_cert_info(
1403 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1404 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1405{
1406 if (DEBUG)
1407 std::cerr << "Get FW root cert info\n";
1408
1409 // request:
1410 // Byte 1 - certificate ID: request which certificate (ignored)
1411
1412 // response:
1413 // Byte 1-2 - certificate length (little endian)
1414 // Byte 3-10 - serial number (little endian)
1415 // Byte 11 - subject length
1416 // Byte 12-N - subject data
1417
1418 auto cert_info = reinterpret_cast<struct fw_cert_info *>(response);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001419 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1420 auto method = bus->new_method_call(
Vernon Mauery52ce6622019-05-22 09:19:46 -07001421 FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_INFO_PATH,
1422 "org.freedesktop.DBus.Properties", "GetAll");
1423 method.append(FW_UPDATE_SECURITY_INTERFACE);
1424 std::string subject;
1425 uint64_t serial;
1426 std::string cert;
1427 try
1428 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001429 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001430
1431 std::vector<std::pair<std::string, ipmi::DbusVariant>> properties;
1432 reply.read(properties);
1433
1434 for (const auto &t : properties)
1435 {
1436 auto key = t.first;
1437 auto value = t.second;
1438 if (key == "certificate_subject")
1439 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001440 subject = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001441 }
1442 else if (key == "cetificate_serial")
1443 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001444 serial = std::get<uint64_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001445 }
1446 else if (key == "certificate")
1447 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001448 cert = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001449 }
1450 }
1451 }
1452 catch (sdbusplus::exception::SdBusError &e)
1453 {
1454 std::cerr << "SDBus Error: " << e.what();
1455 return IPMI_CC_UNSPECIFIED_ERROR;
1456 }
1457
1458 cert_info->cert_len = cert.size();
1459 cert_info->serial = serial;
1460 // truncate subject so it fits in the 255-byte array (if necessary)
1461 if (subject.size() > sizeof(cert_info->subject))
1462 subject.resize(sizeof(cert_info->subject));
1463 cert_info->subject_len = subject.size();
1464 std::copy(subject.begin(), subject.end(), cert_info->subject);
1465
1466 // Status code.
1467 ipmi_ret_t rc = IPMI_CC_OK;
1468 // make sure to account for the *actual* size of the subject
1469 *data_len = sizeof(*cert_info) - sizeof(cert_info->subject) +
1470 cert_info->subject_len;
1471
1472 return rc;
1473}
1474
1475struct fw_cert_data_req
1476{
1477 uint8_t cert_id;
1478 uint16_t offset;
1479 uint16_t count;
1480} __attribute__((packed));
1481
1482static ipmi_ret_t ipmi_firmware_get_root_cert_data(
1483 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1484 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1485{
1486 if (DEBUG)
1487 std::cerr << "Get FW root cert data\n";
1488
1489 // request:
1490 // Byte 1 - certificate ID: request which certificate (ignored)
1491 // Byte 2-3 - offset within cert to start at
1492 // Byte 4-5 - number of bytes to return
1493
1494 // response:
1495 // Byte 1-N - certificate data
1496
1497 if (*data_len != sizeof(fw_cert_data_req))
1498 return IPMI_CC_REQ_DATA_LEN_INVALID;
1499
1500 auto cert_data_req = reinterpret_cast<struct fw_cert_data_req *>(request);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001501 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1502 auto method = bus->new_method_call(
Vernon Mauery52ce6622019-05-22 09:19:46 -07001503 FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_INFO_PATH,
1504 "org.freedesktop.DBus.Properties", "Get");
1505 method.append(FW_UPDATE_SECURITY_INTERFACE, "certificate");
1506 ipmi::DbusVariant cert;
1507 try
1508 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001509 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001510 reply.read(cert);
1511 }
1512 catch (sdbusplus::exception::SdBusError &e)
1513 {
1514 std::cerr << "SDBus Error: " << e.what();
1515 return IPMI_CC_UNSPECIFIED_ERROR;
1516 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001517 auto cert_data = std::get<std::string>(cert);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001518
1519 if (cert_data_req->offset >= cert_data.size())
1520 {
1521 *data_len = 0;
1522 return IPMI_CC_INVALID_FIELD_REQUEST;
1523 }
1524 auto first = cert_data.begin() + cert_data_req->offset;
1525 auto last = first + cert_data_req->count;
1526 if (last > cert_data.end())
1527 last = cert_data.end();
1528
1529 auto data_out = reinterpret_cast<char *>(response);
1530 std::copy(first, last, data_out);
1531
1532 // Status code.
1533 ipmi_ret_t rc = IPMI_CC_OK;
1534 *data_len = (last - first);
1535
1536 return rc;
1537}
1538
1539static ipmi_ret_t ipmi_firmware_write_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1540 ipmi_request_t request,
1541 ipmi_response_t response,
1542 ipmi_data_len_t data_len,
1543 ipmi_context_t context)
1544{
1545 if (DEBUG)
1546 std::cerr << "write fw data (" << *data_len << " bytes)\n";
1547
1548 auto bytes_in = *data_len;
1549 *data_len = 0;
1550 if (fw_update_status.state() != fw_update_status_cache::FW_STATE_DOWNLOAD)
1551 return IPMI_CC_INVALID;
1552
1553 std::ofstream out(FIRMWARE_BUFFER_FILE,
1554 std::ofstream::binary | std::ofstream::app);
1555 if (!out)
1556 {
1557 return IPMI_CC_UNSPECIFIED_ERROR;
1558 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301559
1560 uint64_t fileDataLen = out.tellp();
1561 if (fileDataLen > FIRMWARE_BUFFER_MAX_SIZE)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001562 {
1563 return IPMI_CC_INVALID_FIELD_REQUEST;
1564 }
1565 auto data = reinterpret_cast<uint8_t *>(request);
1566 out.write(reinterpret_cast<char *>(data), bytes_in);
1567 out.close();
1568 if (xfer_hash_check)
1569 {
1570 xfer_hash_check->hash({data, data + bytes_in});
1571 }
1572
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301573#ifdef INTEL_PFR_ENABLED
1574 /* PFR image block 0 - As defined in HAS */
1575 struct PFRImageBlock0
1576 {
1577 uint32_t tag;
1578 uint32_t pcLength;
1579 uint32_t pcType;
1580 uint32_t reserved1;
1581 uint8_t hash256[32];
1582 uint8_t hash384[48];
1583 uint8_t reserved2[32];
1584 } __attribute__((packed));
1585
1586 /* Get the PFR block 0 data and read the uploaded image
1587 * information( Image type, length etc) */
1588 if ((fileDataLen >= sizeof(PFRImageBlock0)) && (!block0Mapped))
1589 {
1590 struct PFRImageBlock0 block0Data = {0};
1591
1592 std::ifstream inFile(FIRMWARE_BUFFER_FILE,
1593 std::ios::binary | std::ios::in);
1594 inFile.read(reinterpret_cast<char *>(&block0Data), sizeof(block0Data));
1595 inFile.close();
1596
1597 uint32_t magicNum = block0Data.tag;
1598
1599 /* Validate the magic number */
1600 if (magicNum != perBlock0MagicNum)
1601 {
1602 return IPMI_CC_INVALID_FIELD_REQUEST;
1603 }
1604 // Note:imgLength, imgType and block0Mapped are in global scope, as
1605 // these are used in cascaded updates.
1606 imgLength = block0Data.pcLength;
1607 imgType = block0Data.pcType;
1608 block0Mapped = true;
1609 }
1610#endif // end of INTEL_PFR_ENABLED
Vernon Mauery52ce6622019-05-22 09:19:46 -07001611 return IPMI_CC_OK;
1612}
1613
Vernon Mauery52ce6622019-05-22 09:19:46 -07001614struct intc_app_get_buffer_size_resp
1615{
1616 uint8_t kcs_size;
1617 uint8_t ipmb_size;
1618} __attribute__((packed));
1619
1620static constexpr int KCS_MAX_BUFFER_SIZE = 63;
1621static constexpr int IPMB_MAX_BUFFER_SIZE = 128;
1622static ipmi_ret_t ipmi_intel_app_get_buffer_size(
1623 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1624 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1625{
1626 auto msg_reply =
1627 reinterpret_cast<intc_app_get_buffer_size_resp *>(response);
1628 // for now this is hard coded; really this number is dependent on
1629 // the BMC kcs driver as well as the host kcs driver....
1630 // we can't know the latter.
1631 msg_reply->kcs_size = KCS_MAX_BUFFER_SIZE / 4;
1632 msg_reply->ipmb_size = IPMB_MAX_BUFFER_SIZE / 4;
1633 *data_len = sizeof(*msg_reply);
1634
1635 return IPMI_CC_OK;
1636}
1637
1638static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_VERSION_INFO = 0x20;
1639static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_SEC_VERSION_INFO = 0x21;
1640static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_UPD_CHAN_INFO = 0x22;
1641static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_BMC_EXEC_CTX = 0x23;
1642static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_ROOT_CERT_INFO = 0x24;
1643static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_ROOT_CERT_DATA = 0x25;
1644static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_UPDATE_RAND_NUM = 0x26;
1645static constexpr ipmi_cmd_t IPMI_CMD_FW_SET_FW_UPDATE_MODE = 0x27;
anil kumar appanab57098a2019-05-28 16:22:33 +00001646static constexpr ipmi_cmd_t cmdFirmwareExitFirmwareUpdateMode = 0x28;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001647static constexpr ipmi_cmd_t IPMI_CMD_FW_UPDATE_CONTROL = 0x29;
1648static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_STATUS = 0x2a;
1649static constexpr ipmi_cmd_t IPMI_CMD_FW_SET_FW_UPDATE_OPTIONS = 0x2b;
1650static constexpr ipmi_cmd_t IPMI_CMD_FW_IMAGE_WRITE = 0x2c;
1651static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_TIMESTAMP = 0x2d;
1652static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_UPDATE_ERR_MSG = 0xe0;
1653static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_REMOTE_FW_INFO = 0xf0;
1654
1655static constexpr ipmi_netfn_t NETFUN_INTC_APP = 0x30;
1656static constexpr ipmi_cmd_t IPMI_CMD_INTC_GET_BUFFER_SIZE = 0x66;
1657
1658static void register_netfn_firmware_functions()
1659{
1660 // guarantee that we start with an already timed out timestamp
1661 fw_random_number_timestamp =
1662 std::chrono::steady_clock::now() - FW_RANDOM_NUMBER_TTL;
1663
1664 unlink(FIRMWARE_BUFFER_FILE);
1665
1666 // <Get BT Interface Capabilities>
1667 if (DEBUG)
1668 std::cerr << "Registering firmware update commands\n";
1669
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301670#ifdef INTEL_PFR_ENABLED
1671 // Following commands are supported only for PFR enabled platforms
1672 // CMD:0x20 - Get Firmware Version Information
Vernon Mauery52ce6622019-05-22 09:19:46 -07001673
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301674 // get firmware version information
1675 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1676 ipmi::firmware::cmdGetFwVersionInfo,
1677 ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
1678#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001679 // get firmware security version information
1680 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_FW_SEC_VERSION_INFO,
1681 NULL, ipmi_firmware_get_fw_security_revision,
1682 PRIVILEGE_ADMIN);
1683
1684 // get channel information (max transfer sizes)
anil kumar appana159547c2019-05-31 16:08:34 +00001685 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1686 IPMI_CMD_FW_GET_FW_UPD_CHAN_INFO,
1687 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001688
1689 // get bmc execution context
1690 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_BMC_EXEC_CTX, NULL,
1691 ipmi_firmware_get_fw_execution_context,
1692 PRIVILEGE_ADMIN);
1693
1694 // get root certificate information
1695 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_ROOT_CERT_INFO,
1696 NULL, ipmi_firmware_get_root_cert_info,
1697 PRIVILEGE_ADMIN);
1698
1699 // get root certificate data
1700 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_ROOT_CERT_DATA,
1701 NULL, ipmi_firmware_get_root_cert_data,
1702 PRIVILEGE_ADMIN);
1703
1704 // generate bmc fw update random number (for enter fw tranfer mode)
1705 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_FW_UPDATE_RAND_NUM,
1706 NULL, ipmi_firmware_get_fw_random_number,
1707 PRIVILEGE_ADMIN);
1708
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301709 // Set Firmware Update Mode(0x27)
1710 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1711 IPMI_CMD_FW_SET_FW_UPDATE_MODE,
1712 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001713
1714 // exit firmware update mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001715 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1716 cmdFirmwareExitFirmwareUpdateMode,
1717 ipmi::Privilege::Admin, ipmiFirmwareExitFwUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001718
1719 // firmware control mechanism (set filename, usb, etc.)
1720 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_UPDATE_CONTROL, NULL,
1721 ipmi_firmware_control, PRIVILEGE_ADMIN);
1722
1723 // get firmware update status
anil kumar appana6c7d9382019-05-31 14:33:13 +00001724 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1725 IPMI_CMD_FW_GET_STATUS, ipmi::Privilege::Admin,
1726 ipmiFrmwareGetStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001727 // set firmware update options (no downgrade, etc.)
1728 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_SET_FW_UPDATE_OPTIONS,
1729 NULL, ipmi_firmware_update_options, PRIVILEGE_ADMIN);
1730
1731 // write image data
1732 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_IMAGE_WRITE, NULL,
1733 ipmi_firmware_write_data, PRIVILEGE_ADMIN);
1734
Vernon Mauery52ce6622019-05-22 09:19:46 -07001735 // get buffer size is used by fw update (exclusively?)
1736 ipmi_register_callback(NETFUN_INTC_APP, IPMI_CMD_INTC_GET_BUFFER_SIZE, NULL,
1737 ipmi_intel_app_get_buffer_size, PRIVILEGE_USER);
1738 return;
1739}