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