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