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