1 /* 2 * Copyright (c) 2018 Intel Corporation. 3 * Copyright (c) 2018-present Facebook. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include "xyz/openbmc_project/Common/error.hpp" 19 20 #include <boost/crc.hpp> 21 #include <commandutils.hpp> 22 #include <ipmid/api-types.hpp> 23 #include <ipmid/api.hpp> 24 #include <ipmid/utils.hpp> 25 #include <nlohmann/json.hpp> 26 #include <oemcommands.hpp> 27 #include <phosphor-logging/log.hpp> 28 #include <sdbusplus/bus.hpp> 29 #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> 30 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> 31 #include <xyz/openbmc_project/Control/Boot/Type/server.hpp> 32 33 #include <array> 34 #include <cstring> 35 #include <fstream> 36 #include <functional> 37 #include <iomanip> 38 #include <iostream> 39 #include <optional> 40 #include <regex> 41 #include <sstream> 42 #include <string> 43 #include <vector> 44 45 #define SIZE_IANA_ID 3 46 47 namespace ipmi 48 { 49 50 using namespace phosphor::logging; 51 52 void getSelectorPosition(size_t& position); 53 static void registerOEMFunctions() __attribute__((constructor)); 54 sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h 55 static constexpr size_t maxFRUStringLength = 0x3F; 56 constexpr uint8_t cmdSetSystemGuid = 0xEF; 57 58 constexpr uint8_t cmdSetQDimmInfo = 0x12; 59 constexpr uint8_t cmdGetQDimmInfo = 0x13; 60 61 constexpr ipmi_ret_t ccInvalidParam = 0x80; 62 63 int plat_udbg_get_post_desc(uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*, 64 uint8_t*); 65 int plat_udbg_get_gpio_desc(uint8_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*, 66 uint8_t*); 67 int plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t*, uint8_t*, uint8_t*); 68 ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t*, 69 uint8_t*); 70 int sendMeCmd(uint8_t, uint8_t, std::vector<uint8_t>&, std::vector<uint8_t>&); 71 72 int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&, 73 std::vector<uint8_t>&); 74 75 nlohmann::json oemData __attribute__((init_priority(101))); 76 77 constexpr const char* certPath = "/mnt/data/host/bios-rootcert"; 78 79 static constexpr size_t GUID_SIZE = 16; 80 // TODO Make offset and location runtime configurable to ensure we 81 // can make each define their own locations. 82 static constexpr off_t OFFSET_SYS_GUID = 0x17F0; 83 static constexpr const char* FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom"; 84 void flushOemData(); 85 86 enum class LanParam : uint8_t 87 { 88 INPROGRESS = 0, 89 AUTHSUPPORT = 1, 90 AUTHENABLES = 2, 91 IP = 3, 92 IPSRC = 4, 93 MAC = 5, 94 SUBNET = 6, 95 GATEWAY = 12, 96 VLAN = 20, 97 CIPHER_SUITE_COUNT = 22, 98 CIPHER_SUITE_ENTRIES = 23, 99 IPV6 = 59, 100 }; 101 102 namespace network 103 { 104 105 constexpr auto ROOT = "/xyz/openbmc_project/network"; 106 constexpr auto SERVICE = "xyz.openbmc_project.Network"; 107 constexpr auto IPV4_TYPE = "ipv4"; 108 constexpr auto IPV6_TYPE = "ipv6"; 109 constexpr auto IPV4_PREFIX = "169.254"; 110 constexpr auto IPV6_PREFIX = "fe80"; 111 constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; 112 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; 113 constexpr auto IPV4_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; 114 constexpr auto IPV6_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; 115 116 bool isLinkLocalIP(const std::string& address) 117 { 118 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0; 119 } 120 121 DbusObjectInfo getIPObject(sdbusplus::bus_t& bus, const std::string& interface, 122 const std::string& serviceRoot, 123 const std::string& protocol, 124 const std::string& ethdev) 125 { 126 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, ethdev); 127 128 if (objectTree.empty()) 129 { 130 log<level::ERR>("No Object has implemented the IP interface", 131 entry("INTERFACE=%s", interface.c_str())); 132 } 133 134 DbusObjectInfo objectInfo; 135 136 for (auto& object : objectTree) 137 { 138 auto variant = 139 ipmi::getDbusProperty(bus, object.second.begin()->first, 140 object.first, IP_INTERFACE, "Type"); 141 if (std::get<std::string>(variant) != protocol) 142 { 143 continue; 144 } 145 146 variant = ipmi::getDbusProperty(bus, object.second.begin()->first, 147 object.first, IP_INTERFACE, "Address"); 148 149 objectInfo = std::make_pair(object.first, object.second.begin()->first); 150 151 // if LinkLocalIP found look for Non-LinkLocalIP 152 if (isLinkLocalIP(std::get<std::string>(variant))) 153 { 154 continue; 155 } 156 else 157 { 158 break; 159 } 160 } 161 return objectInfo; 162 } 163 164 } // namespace network 165 166 namespace boot 167 { 168 using BootSource = 169 sdbusplus::xyz::openbmc_project::Control::Boot::server::Source::Sources; 170 using BootMode = 171 sdbusplus::xyz::openbmc_project::Control::Boot::server::Mode::Modes; 172 using BootType = 173 sdbusplus::xyz::openbmc_project::Control::Boot::server::Type::Types; 174 175 using IpmiValue = uint8_t; 176 177 std::map<IpmiValue, BootSource> sourceIpmiToDbus = { 178 {0x0f, BootSource::Default}, {0x00, BootSource::RemovableMedia}, 179 {0x01, BootSource::Network}, {0x02, BootSource::Disk}, 180 {0x03, BootSource::ExternalMedia}, {0x04, BootSource::RemovableMedia}, 181 {0x09, BootSource::Network}}; 182 183 std::map<IpmiValue, BootMode> modeIpmiToDbus = {{0x04, BootMode::Setup}, 184 {0x00, BootMode::Regular}}; 185 186 std::map<IpmiValue, BootType> typeIpmiToDbus = {{0x00, BootType::Legacy}, 187 {0x01, BootType::EFI}}; 188 189 std::map<std::optional<BootSource>, IpmiValue> sourceDbusToIpmi = { 190 {BootSource::Default, 0x0f}, 191 {BootSource::RemovableMedia, 0x00}, 192 {BootSource::Network, 0x01}, 193 {BootSource::Disk, 0x02}, 194 {BootSource::ExternalMedia, 0x03}}; 195 196 std::map<std::optional<BootMode>, IpmiValue> modeDbusToIpmi = { 197 {BootMode::Setup, 0x04}, {BootMode::Regular, 0x00}}; 198 199 std::map<std::optional<BootType>, IpmiValue> typeDbusToIpmi = { 200 {BootType::Legacy, 0x00}, {BootType::EFI, 0x01}}; 201 202 static constexpr auto bootEnableIntf = "xyz.openbmc_project.Object.Enable"; 203 static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; 204 static constexpr auto bootSourceIntf = 205 "xyz.openbmc_project.Control.Boot.Source"; 206 static constexpr auto bootTypeIntf = "xyz.openbmc_project.Control.Boot.Type"; 207 static constexpr auto bootSourceProp = "BootSource"; 208 static constexpr auto bootModeProp = "BootMode"; 209 static constexpr auto bootTypeProp = "BootType"; 210 static constexpr auto bootEnableProp = "Enabled"; 211 212 std::tuple<std::string, std::string> objPath(size_t id) 213 { 214 std::string hostName = "host" + std::to_string(id); 215 std::string bootObjPath = 216 "/xyz/openbmc_project/control/" + hostName + "/boot"; 217 return std::make_tuple(std::move(bootObjPath), std::move(hostName)); 218 } 219 220 /* Helper functions to set boot order */ 221 void setBootOrder(std::string bootObjPath, const std::vector<uint8_t>& bootSeq, 222 std::string bootOrderKey) 223 { 224 if (bootSeq.size() != SIZE_BOOT_ORDER) 225 { 226 phosphor::logging::log<phosphor::logging::level::ERR>( 227 "Invalid Boot order length received"); 228 return; 229 } 230 231 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 232 233 uint8_t mode = bootSeq.front(); 234 235 // SETTING BOOT MODE PROPERTY 236 uint8_t bootModeBit = mode & 0x04; 237 auto bootValue = ipmi::boot::modeIpmiToDbus.at(bootModeBit); 238 239 std::string bootOption = 240 sdbusplus::message::convert_to_string<boot::BootMode>(bootValue); 241 242 std::string service = 243 getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath); 244 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf, 245 ipmi::boot::bootModeProp, bootOption); 246 247 // SETTING BOOT SOURCE PROPERTY 248 auto bootOrder = ipmi::boot::sourceIpmiToDbus.at(bootSeq.at(1)); 249 std::string bootSource = 250 sdbusplus::message::convert_to_string<boot::BootSource>(bootOrder); 251 252 service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath); 253 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf, 254 ipmi::boot::bootSourceProp, bootSource); 255 256 // SETTING BOOT TYPE PROPERTY 257 uint8_t bootTypeBit = mode & 0x01; 258 auto bootTypeVal = ipmi::boot::typeIpmiToDbus.at(bootTypeBit); 259 260 std::string bootType = 261 sdbusplus::message::convert_to_string<boot::BootType>(bootTypeVal); 262 263 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath); 264 265 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf, 266 ipmi::boot::bootTypeProp, bootType); 267 268 // Set the valid bit to boot enabled property 269 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath); 270 271 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf, 272 ipmi::boot::bootEnableProp, 273 (mode & BOOT_MODE_BOOT_FLAG) ? true : false); 274 275 nlohmann::json bootMode; 276 277 bootMode["UEFI"] = (mode & BOOT_MODE_UEFI) ? true : false; 278 bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR) ? true : false; 279 bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT) ? true : false; 280 bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG) ? true : false; 281 oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode; 282 283 /* Initialize boot sequence array */ 284 oemData[bootOrderKey][KEY_BOOT_SEQ] = {}; 285 for (size_t i = 1; i < SIZE_BOOT_ORDER; i++) 286 { 287 if (bootSeq.at(i) >= BOOT_SEQ_ARRAY_SIZE) 288 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA"; 289 else 290 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = 291 bootSeqDefine[bootSeq.at(i)]; 292 } 293 294 flushOemData(); 295 } 296 297 void getBootOrder(std::string bootObjPath, std::vector<uint8_t>& bootSeq, 298 std::string hostName) 299 { 300 if (oemData.find(hostName) == oemData.end()) 301 { 302 /* Return default boot order 0100090203ff */ 303 bootSeq.push_back(BOOT_MODE_UEFI); 304 bootSeq.push_back(static_cast<uint8_t>(bootMap["USB_DEV"])); 305 bootSeq.push_back(static_cast<uint8_t>(bootMap["NET_IPV6"])); 306 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_HDD"])); 307 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_CD"])); 308 bootSeq.push_back(0xff); 309 310 phosphor::logging::log<phosphor::logging::level::INFO>( 311 "Set default boot order"); 312 setBootOrder(bootObjPath, bootSeq, hostName); 313 return; 314 } 315 316 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 317 318 // GETTING PROPERTY OF MODE INTERFACE 319 320 std::string service = 321 getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath); 322 Value variant = 323 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf, 324 ipmi::boot::bootModeProp); 325 326 auto bootMode = sdbusplus::message::convert_from_string<boot::BootMode>( 327 std::get<std::string>(variant)); 328 329 uint8_t bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode); 330 331 // GETTING PROPERTY OF TYPE INTERFACE 332 333 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath); 334 variant = 335 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf, 336 ipmi::boot::bootTypeProp); 337 338 auto bootType = sdbusplus::message::convert_from_string<boot::BootType>( 339 std::get<std::string>(variant)); 340 341 // Get the valid bit to boot enabled property 342 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath); 343 variant = 344 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf, 345 ipmi::boot::bootEnableProp); 346 347 bool validFlag = std::get<bool>(variant); 348 349 uint8_t bootTypeVal = ipmi::boot::typeDbusToIpmi.at(bootType); 350 351 bootSeq.push_back(bootOption | bootTypeVal); 352 353 if (validFlag) 354 { 355 bootSeq.front() |= BOOT_MODE_BOOT_FLAG; 356 } 357 358 nlohmann::json bootModeJson = oemData[hostName][KEY_BOOT_MODE]; 359 if (bootModeJson["CMOS_CLR"]) 360 bootSeq.front() |= BOOT_MODE_CMOS_CLR; 361 362 for (int i = 1; i < SIZE_BOOT_ORDER; i++) 363 { 364 std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1]; 365 if (bootMap.find(seqStr) != bootMap.end()) 366 bootSeq.push_back(bootMap[seqStr]); 367 else 368 bootSeq.push_back(0xff); 369 } 370 } 371 372 } // namespace boot 373 374 //---------------------------------------------------------------------- 375 // Helper functions for storing oem data 376 //---------------------------------------------------------------------- 377 378 void flushOemData() 379 { 380 std::ofstream file(JSON_OEM_DATA_FILE); 381 file << oemData; 382 file.close(); 383 return; 384 } 385 386 std::string bytesToStr(uint8_t* byte, int len) 387 { 388 std::stringstream ss; 389 int i; 390 391 ss << std::hex; 392 for (i = 0; i < len; i++) 393 { 394 ss << std::setw(2) << std::setfill('0') << (int)byte[i]; 395 } 396 397 return ss.str(); 398 } 399 400 int strToBytes(std::string& str, uint8_t* data) 401 { 402 std::string sstr; 403 size_t i; 404 405 for (i = 0; i < (str.length()) / 2; i++) 406 { 407 sstr = str.substr(i * 2, 2); 408 data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16); 409 } 410 return i; 411 } 412 413 int readDimmType(std::string& data, uint8_t param) 414 { 415 nlohmann::json dimmObj; 416 /* Get dimm type names stored in json file */ 417 std::ifstream file(JSON_DIMM_TYPE_FILE); 418 if (file) 419 { 420 file >> dimmObj; 421 file.close(); 422 } 423 else 424 { 425 phosphor::logging::log<phosphor::logging::level::ERR>( 426 "DIMM type names file not found", 427 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE)); 428 return -1; 429 } 430 431 std::string dimmKey = "dimm_type" + std::to_string(param); 432 auto obj = dimmObj[dimmKey]["short_name"]; 433 data = obj; 434 return 0; 435 } 436 437 static std::optional<std::string> findIpAddress( 438 sdbusplus::bus_t& bus, const std::string& protocol, 439 const std::vector<std::string>& ifaces) 440 { 441 for (auto& dev : ifaces) 442 { 443 try 444 { 445 auto ipObjectInfo = 446 ipmi::network::getIPObject(bus, ipmi::network::IP_INTERFACE, 447 ipmi::network::ROOT, protocol, dev); 448 449 auto props = ipmi::getAllDbusProperties( 450 bus, ipObjectInfo.second, ipObjectInfo.first, 451 ipmi::network::IP_INTERFACE); 452 453 auto addr = std::get<std::string>(props.at("Address")); 454 if (!addr.empty()) 455 return addr; 456 } 457 catch (const sdbusplus::exception::SdBusError&) 458 {} 459 } 460 return std::nullopt; 461 } 462 static std::optional<std::string> findMacAddress( 463 sdbusplus::bus_t& bus, const std::vector<std::string>& ifaces) 464 { 465 for (auto& dev : ifaces) 466 { 467 try 468 { 469 auto [path, obj] = ipmi::getDbusObject( 470 bus, ipmi::network::MAC_INTERFACE, ipmi::network::ROOT, dev); 471 472 auto var = ipmi::getDbusProperty( 473 bus, obj, path, ipmi::network::MAC_INTERFACE, "MACAddress"); 474 475 auto mac = std::get<std::string>(var); 476 if (!mac.empty()) 477 return mac; 478 } 479 catch (const sdbusplus::exception::SdBusError&) 480 {} 481 } 482 return std::nullopt; 483 } 484 485 ipmi_ret_t getNetworkData(uint8_t lan_param, char* data) 486 { 487 static const std::vector<std::string> ifaces{"eth0", "eth1"}; 488 489 sdbusplus::bus_t bus(ipmid_get_sd_bus_connection()); 490 ipmi_ret_t rc = IPMI_CC_OK; 491 std::optional<std::string> result; 492 493 switch (static_cast<LanParam>(lan_param)) 494 { 495 case LanParam::IP: 496 result = findIpAddress(bus, ipmi::network::IPV4_PROTOCOL, ifaces); 497 lg2::info("Found IP Address: {ADDR}", "ADDR", 498 result.value_or("Not Found")); 499 break; 500 501 case LanParam::IPV6: 502 result = findIpAddress(bus, ipmi::network::IPV6_PROTOCOL, ifaces); 503 lg2::info("Found IPv6 Address: {ADDR}", "ADDR", 504 result.value_or("Not Found")); 505 break; 506 507 case LanParam::MAC: 508 result = findMacAddress(bus, ifaces); 509 lg2::info("Found MAC Address: {ADDR}", "ADDR", 510 result.value_or("Not Found")); 511 break; 512 513 default: 514 return IPMI_CC_PARM_OUT_OF_RANGE; 515 } 516 517 if (!result.has_value()) 518 { 519 rc = IPMI_CC_UNSPECIFIED_ERROR; 520 data[0] = '\0'; 521 } 522 else 523 { 524 std::strcpy(data, result->c_str()); 525 } 526 return rc; 527 } 528 529 bool isMultiHostPlatform() 530 { 531 bool platform; 532 if (hostInstances == "0") 533 { 534 platform = false; 535 } 536 else 537 { 538 platform = true; 539 } 540 return platform; 541 } 542 static std::optional<std::string> findFruPathByInterface( 543 sdbusplus::bus_t& dbus, const std::string& interfaceName, 544 std::function<bool(const std::string&)> predicate) 545 { 546 const int depth = 0; 547 std::vector<std::string> paths; 548 549 auto mapperCall = dbus.new_method_call( 550 "xyz.openbmc_project.ObjectMapper", 551 "/xyz/openbmc_project/object_mapper", 552 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths"); 553 mapperCall.append("/xyz/openbmc_project/inventory/", depth, 554 std::array<const char*, 1>{interfaceName.c_str()}); 555 556 try 557 { 558 auto reply = dbus.call(mapperCall); 559 reply.read(paths); 560 } 561 catch (const sdbusplus::exception_t& e) 562 { 563 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 564 return std::nullopt; 565 } 566 567 for (const auto& path : paths) 568 { 569 if (predicate(path)) 570 { 571 return path; 572 } 573 } 574 return std::nullopt; 575 } 576 577 // return "" equals failed 578 std::string getMotherBoardFruPath() 579 { 580 sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection()); 581 582 bool platform = isMultiHostPlatform(); 583 size_t hostPosition; 584 if (platform) 585 getSelectorPosition(hostPosition); 586 587 if (hostPosition == 0) 588 { 589 if (auto path = findFruPathByInterface( 590 dbus, "xyz.openbmc_project.Inventory.Item.Bmc", 591 [](const std::string&) { return true; })) 592 { 593 lg2::info("[1] Found Motherboard: {PATH}", "PATH", *path); 594 return *path; 595 } 596 } 597 598 size_t targetIndex = (hostPosition > 0 ? hostPosition - 1 : 0); 599 auto predNth = [targetIndex, 600 counter = size_t{0}](const std::string& /*path*/) mutable { 601 return (counter++ == targetIndex); 602 }; 603 604 if (auto path = findFruPathByInterface( 605 dbus, "xyz.openbmc_project.Inventory.Item.Board.Motherboard", 606 predNth)) 607 { 608 lg2::info("[2] Found Motherboard: {PATH}", "PATH", *path); 609 return *path; 610 } 611 612 phosphor::logging::log<phosphor::logging::level::ERR>( 613 "getMotherBoardFruPath: no valid FRU path found"); 614 return ""; 615 } 616 617 // return "" equals failed 618 std::string getMotherBoardFruName() 619 { 620 std::string path = getMotherBoardFruPath(); 621 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 622 std::string service = "xyz.openbmc_project.EntityManager"; 623 624 try 625 { 626 auto value = ipmi::getDbusProperty( 627 *dbus, service, path, "xyz.openbmc_project.Inventory.Item.Board", 628 "Name"); 629 return std::get<std::string>(value); 630 } 631 catch (sdbusplus::exception_t& e) 632 { 633 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 634 return ""; 635 } 636 } 637 638 // return code: 0 successful 639 int8_t getFruData(std::string& data, std::string& name) 640 { 641 size_t pos; 642 static constexpr const auto depth = 0; 643 std::vector<std::string> paths; 644 std::string machinePath; 645 std::string baseBoard = getMotherBoardFruPath(); 646 baseBoard = baseBoard.empty() ? "Baseboard" : baseBoard; 647 648 bool platform = isMultiHostPlatform(); 649 if (platform == true) 650 { 651 getSelectorPosition(pos); 652 } 653 654 sd_bus* bus = NULL; 655 int ret = sd_bus_default_system(&bus); 656 if (ret < 0) 657 { 658 phosphor::logging::log<phosphor::logging::level::ERR>( 659 "Failed to connect to system bus", 660 phosphor::logging::entry("ERRNO=0x%X", -ret)); 661 sd_bus_unref(bus); 662 return -1; 663 } 664 sdbusplus::bus_t dbus(bus); 665 auto mapperCall = dbus.new_method_call( 666 "xyz.openbmc_project.ObjectMapper", 667 "/xyz/openbmc_project/object_mapper", 668 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths"); 669 static constexpr std::array<const char*, 1> interface = { 670 "xyz.openbmc_project.Inventory.Decorator.Asset"}; 671 mapperCall.append("/xyz/openbmc_project/inventory/", depth, interface); 672 673 try 674 { 675 auto reply = dbus.call(mapperCall); 676 reply.read(paths); 677 } 678 catch (sdbusplus::exception_t& e) 679 { 680 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 681 return -1; 682 } 683 684 for (const auto& path : paths) 685 { 686 if (platform == true) 687 { 688 if (pos == BMC_POS) 689 { 690 machinePath = baseBoard; 691 } 692 else 693 { 694 machinePath = "_" + std::to_string(pos); 695 } 696 } 697 else 698 { 699 machinePath = baseBoard; 700 } 701 702 auto found = path.find(machinePath); 703 if (found == std::string::npos) 704 { 705 continue; 706 } 707 708 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 709 std::string service = getService( 710 *dbus, "xyz.openbmc_project.Inventory.Decorator.Asset", path); 711 712 auto Value = ipmi::getDbusProperty( 713 *dbus, service, path, 714 "xyz.openbmc_project.Inventory.Decorator.Asset", name); 715 716 data = std::get<std::string>(Value); 717 return 0; 718 } 719 return -1; 720 } 721 722 int8_t sysConfig(std::vector<std::string>& data, size_t pos) 723 { 724 nlohmann::json sysObj; 725 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(pos); 726 std::string result, typeName; 727 uint8_t res[MAX_BUF]; 728 729 /* Get sysConfig data stored in json file */ 730 std::ifstream file(JSON_OEM_DATA_FILE); 731 if (file) 732 { 733 file >> sysObj; 734 file.close(); 735 } 736 else 737 { 738 phosphor::logging::log<phosphor::logging::level::ERR>( 739 "oemData file not found", 740 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE)); 741 return -1; 742 } 743 744 if (sysObj.find(dimmInfo) == sysObj.end()) 745 { 746 phosphor::logging::log<phosphor::logging::level::ERR>( 747 "sysconfig key not available", 748 phosphor::logging::entry("SYS_JSON_KEY=%s", dimmInfo.c_str())); 749 return -1; 750 } 751 /* Get dimm type names stored in json file */ 752 nlohmann::json dimmObj; 753 std::ifstream dimmFile(JSON_DIMM_TYPE_FILE); 754 if (file) 755 { 756 dimmFile >> dimmObj; 757 dimmFile.close(); 758 } 759 else 760 { 761 phosphor::logging::log<phosphor::logging::level::ERR>( 762 "DIMM type names file not found", 763 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE)); 764 return -1; 765 } 766 std::vector<std::string> a; 767 for (auto& j : dimmObj.items()) 768 { 769 std::string name = j.key(); 770 a.push_back(name); 771 } 772 773 uint8_t len = a.size(); 774 for (uint8_t ii = 0; ii < len; ii++) 775 { 776 std::string indKey = std::to_string(ii); 777 std::string speedSize = sysObj[dimmInfo][indKey][DIMM_SPEED]; 778 strToBytes(speedSize, res); 779 auto speed = (res[1] << 8 | res[0]); 780 size_t dimmSize = ((res[3] << 8 | res[2]) / 1000); 781 782 if (dimmSize == 0) 783 { 784 std::cerr << "Dimm information not available for slot_" + 785 std::to_string(ii) 786 << std::endl; 787 continue; 788 } 789 std::string type = sysObj[dimmInfo][indKey][DIMM_TYPE]; 790 std::string dualInlineMem = sysObj[dimmInfo][indKey][KEY_DIMM_TYPE]; 791 strToBytes(type, res); 792 size_t dimmType = res[0]; 793 if (dimmVenMap.find(dimmType) == dimmVenMap.end()) 794 { 795 typeName = "unknown"; 796 } 797 else 798 { 799 typeName = dimmVenMap[dimmType]; 800 } 801 result = dualInlineMem + "/" + typeName + "/" + std::to_string(speed) + 802 "MHz" + "/" + std::to_string(dimmSize) + "GB"; 803 data.push_back(result); 804 } 805 return 0; 806 } 807 808 int8_t procInfo(std::string& result, size_t pos) 809 { 810 std::vector<char> data; 811 uint8_t res[MAX_BUF]; 812 std::string procIndex = "00"; 813 nlohmann::json proObj; 814 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(pos); 815 /* Get processor data stored in json file */ 816 std::ifstream file(JSON_OEM_DATA_FILE); 817 if (file) 818 { 819 file >> proObj; 820 file.close(); 821 } 822 else 823 { 824 phosphor::logging::log<phosphor::logging::level::ERR>( 825 "oemData file not found", 826 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE)); 827 return -1; 828 } 829 if (proObj.find(procInfo) == proObj.end()) 830 { 831 phosphor::logging::log<phosphor::logging::level::ERR>( 832 "processor info key not available", 833 phosphor::logging::entry("PROC_JSON_KEY=%s", procInfo.c_str())); 834 return -1; 835 } 836 std::string procName = proObj[procInfo][procIndex][KEY_PROC_NAME]; 837 std::string basicInfo = proObj[procInfo][procIndex][KEY_BASIC_INFO]; 838 // Processor Product Name 839 strToBytes(procName, res); 840 data.assign(reinterpret_cast<char*>(&res), 841 reinterpret_cast<char*>(&res) + sizeof(res)); 842 843 std::string s(data.begin(), data.end()); 844 std::regex regex(" "); 845 std::vector<std::string> productName( 846 std::sregex_token_iterator(s.begin(), s.end(), regex, -1), 847 std::sregex_token_iterator()); 848 849 // Processor core and frequency 850 strToBytes(basicInfo, res); 851 uint16_t coreNum = res[0]; 852 double procFrequency = (float)(res[4] << 8 | res[3]) / 1000; 853 result = "CPU:" + productName[2] + "/" + std::to_string(procFrequency) + 854 "GHz" + "/" + std::to_string(coreNum) + "c"; 855 return 0; 856 } 857 858 typedef struct 859 { 860 uint8_t cur_power_state; 861 uint8_t last_power_event; 862 uint8_t misc_power_state; 863 uint8_t front_panel_button_cap_status; 864 } ipmi_get_chassis_status_t; 865 866 //---------------------------------------------------------------------- 867 // Get Debug Frame Info 868 //---------------------------------------------------------------------- 869 ipmi_ret_t ipmiOemDbgGetFrameInfo( 870 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, 871 ipmi_data_len_t data_len, ipmi_context_t) 872 { 873 uint8_t* req = reinterpret_cast<uint8_t*>(request); 874 uint8_t* res = reinterpret_cast<uint8_t*>(response); 875 uint8_t num_frames = debugCardFrameSize; 876 877 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID 878 res[SIZE_IANA_ID] = num_frames; 879 *data_len = SIZE_IANA_ID + 1; 880 881 return ipmi::ccSuccess; 882 } 883 884 //---------------------------------------------------------------------- 885 // Get Debug Updated Frames 886 //---------------------------------------------------------------------- 887 ipmi_ret_t ipmiOemDbgGetUpdFrames( 888 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, 889 ipmi_data_len_t data_len, ipmi_context_t) 890 { 891 uint8_t* req = reinterpret_cast<uint8_t*>(request); 892 uint8_t* res = reinterpret_cast<uint8_t*>(response); 893 uint8_t num_updates = 3; 894 *data_len = 4; 895 896 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID 897 res[SIZE_IANA_ID] = num_updates; 898 *data_len = SIZE_IANA_ID + num_updates + 1; 899 res[SIZE_IANA_ID + 1] = 1; // info page update 900 res[SIZE_IANA_ID + 2] = 2; // cri sel update 901 res[SIZE_IANA_ID + 3] = 3; // cri sensor update 902 903 return ipmi::ccSuccess; 904 } 905 906 //---------------------------------------------------------------------- 907 // Get Debug POST Description 908 //---------------------------------------------------------------------- 909 ipmi_ret_t ipmiOemDbgGetPostDesc( 910 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, 911 ipmi_data_len_t data_len, ipmi_context_t) 912 { 913 uint8_t* req = reinterpret_cast<uint8_t*>(request); 914 uint8_t* res = reinterpret_cast<uint8_t*>(response); 915 uint8_t index = 0; 916 uint8_t next = 0; 917 uint8_t end = 0; 918 uint8_t phase = 0; 919 uint8_t descLen = 0; 920 int ret; 921 922 index = req[3]; 923 phase = req[4]; 924 925 ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]); 926 if (ret) 927 { 928 memcpy(res, req, SIZE_IANA_ID); // IANA ID 929 *data_len = SIZE_IANA_ID; 930 return ipmi::ccUnspecifiedError; 931 } 932 933 memcpy(res, req, SIZE_IANA_ID); // IANA ID 934 res[3] = index; 935 res[4] = next; 936 res[5] = phase; 937 res[6] = end; 938 res[7] = descLen; 939 *data_len = SIZE_IANA_ID + 5 + descLen; 940 941 return ipmi::ccSuccess; 942 } 943 944 //---------------------------------------------------------------------- 945 // Get Debug GPIO Description 946 //---------------------------------------------------------------------- 947 ipmi_ret_t ipmiOemDbgGetGpioDesc( 948 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, 949 ipmi_data_len_t data_len, ipmi_context_t) 950 { 951 uint8_t* req = reinterpret_cast<uint8_t*>(request); 952 uint8_t* res = reinterpret_cast<uint8_t*>(response); 953 954 uint8_t index = 0; 955 uint8_t next = 0; 956 uint8_t level = 0; 957 uint8_t pinDef = 0; 958 uint8_t descLen = 0; 959 int ret; 960 961 index = req[3]; 962 963 ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen, 964 &res[8]); 965 if (ret) 966 { 967 memcpy(res, req, SIZE_IANA_ID); // IANA ID 968 *data_len = SIZE_IANA_ID; 969 return ipmi::ccUnspecifiedError; 970 } 971 972 memcpy(res, req, SIZE_IANA_ID); // IANA ID 973 res[3] = index; 974 res[4] = next; 975 res[5] = level; 976 res[6] = pinDef; 977 res[7] = descLen; 978 *data_len = SIZE_IANA_ID + 5 + descLen; 979 980 return ipmi::ccSuccess; 981 } 982 983 //---------------------------------------------------------------------- 984 // Get Debug Frame Data 985 //---------------------------------------------------------------------- 986 ipmi_ret_t ipmiOemDbgGetFrameData( 987 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, 988 ipmi_data_len_t data_len, ipmi_context_t) 989 { 990 uint8_t* req = reinterpret_cast<uint8_t*>(request); 991 uint8_t* res = reinterpret_cast<uint8_t*>(response); 992 uint8_t frame; 993 uint8_t page; 994 uint8_t next; 995 uint8_t count; 996 int ret; 997 998 frame = req[3]; 999 page = req[4]; 1000 1001 ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]); 1002 if (ret) 1003 { 1004 memcpy(res, req, SIZE_IANA_ID); // IANA ID 1005 *data_len = SIZE_IANA_ID; 1006 return ipmi::ccUnspecifiedError; 1007 } 1008 1009 memcpy(res, req, SIZE_IANA_ID); // IANA ID 1010 res[3] = frame; 1011 res[4] = page; 1012 res[5] = next; 1013 res[6] = count; 1014 *data_len = SIZE_IANA_ID + 4 + count; 1015 1016 return ipmi::ccSuccess; 1017 } 1018 1019 //---------------------------------------------------------------------- 1020 // Get Debug Control Panel 1021 //---------------------------------------------------------------------- 1022 ipmi_ret_t ipmiOemDbgGetCtrlPanel( 1023 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, 1024 ipmi_data_len_t data_len, ipmi_context_t) 1025 { 1026 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1027 uint8_t* res = reinterpret_cast<uint8_t*>(response); 1028 1029 uint8_t panel; 1030 uint8_t operation; 1031 uint8_t item; 1032 uint8_t count; 1033 ipmi_ret_t ret; 1034 1035 panel = req[3]; 1036 operation = req[4]; 1037 item = req[5]; 1038 1039 ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]); 1040 1041 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID 1042 *data_len = SIZE_IANA_ID + count; 1043 1044 return ret; 1045 } 1046 1047 //---------------------------------------------------------------------- 1048 // Set Dimm Info (CMD_OEM_SET_DIMM_INFO) 1049 //---------------------------------------------------------------------- 1050 ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1051 ipmi_response_t, ipmi_data_len_t data_len, 1052 ipmi_context_t) 1053 { 1054 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1055 1056 uint8_t index = req[0]; 1057 uint8_t type = req[1]; 1058 uint16_t speed; 1059 uint32_t size; 1060 1061 memcpy(&speed, &req[2], 2); 1062 memcpy(&size, &req[4], 4); 1063 1064 std::stringstream ss; 1065 ss << std::hex; 1066 ss << std::setw(2) << std::setfill('0') << (int)index; 1067 1068 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index; 1069 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type; 1070 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed; 1071 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size; 1072 1073 flushOemData(); 1074 1075 *data_len = 0; 1076 1077 return ipmi::ccSuccess; 1078 } 1079 1080 //---------------------------------------------------------------------- 1081 // Get Board ID (CMD_OEM_GET_BOARD_ID) 1082 //---------------------------------------------------------------------- 1083 ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1084 ipmi_response_t, ipmi_data_len_t data_len, 1085 ipmi_context_t) 1086 { 1087 /* TODO: Needs to implement this after GPIO implementation */ 1088 *data_len = 0; 1089 1090 return ipmi::ccSuccess; 1091 } 1092 1093 //---------------------------------------------------------------------- 1094 // Get port 80 record (CMD_OEM_GET_80PORT_RECORD) 1095 //---------------------------------------------------------------------- 1096 ipmi::RspType<std::vector<uint8_t>> ipmiOemGet80PortRecord( 1097 ipmi::Context::ptr ctx) 1098 { 1099 auto postCodeService = "xyz.openbmc_project.State.Boot.PostCode" + 1100 std::to_string(ctx->hostIdx + 1); 1101 auto postCodeObjPath = "/xyz/openbmc_project/State/Boot/PostCode" + 1102 std::to_string(ctx->hostIdx + 1); 1103 constexpr auto postCodeInterface = 1104 "xyz.openbmc_project.State.Boot.PostCode"; 1105 const static uint16_t lastestPostCodeIndex = 1; 1106 constexpr const auto maxPostCodeLen = 1107 224; // The length must be lower than IPMB limitation 1108 size_t startIndex = 0; 1109 1110 std::vector<std::tuple<uint64_t, std::vector<uint8_t>>> postCodes; 1111 std::vector<uint8_t> resData; 1112 1113 auto conn = getSdBus(); 1114 /* Get the post codes by calling GetPostCodes method */ 1115 auto msg = 1116 conn->new_method_call(postCodeService.c_str(), postCodeObjPath.c_str(), 1117 postCodeInterface, "GetPostCodes"); 1118 msg.append(lastestPostCodeIndex); 1119 1120 try 1121 { 1122 auto reply = conn->call(msg); 1123 reply.read(postCodes); 1124 } 1125 catch (const sdbusplus::exception::SdBusError& e) 1126 { 1127 phosphor::logging::log<phosphor::logging::level::ERR>( 1128 "IPMI Get80PortRecord Failed in call method", 1129 phosphor::logging::entry("ERROR=%s", e.what())); 1130 return ipmi::responseUnspecifiedError(); 1131 } 1132 1133 /* Get post code data */ 1134 for (size_t i = 0; i < postCodes.size(); ++i) 1135 { 1136 uint64_t primaryPostCode = std::get<uint64_t>(postCodes[i]); 1137 for (int j = postCodeSize - 1; j >= 0; --j) 1138 { 1139 uint8_t postCode = 1140 ((primaryPostCode >> (sizeof(uint64_t) * j)) & 0xFF); 1141 resData.emplace_back(postCode); 1142 } 1143 } 1144 1145 std::vector<uint8_t> response; 1146 if (resData.size() > maxPostCodeLen) 1147 { 1148 startIndex = resData.size() - maxPostCodeLen; 1149 } 1150 1151 response.assign(resData.begin() + startIndex, resData.end()); 1152 1153 return ipmi::responseSuccess(response); 1154 } 1155 1156 //---------------------------------------------------------------------- 1157 // Set Boot Order (CMD_OEM_SET_BOOT_ORDER) 1158 //---------------------------------------------------------------------- 1159 ipmi::RspType<std::vector<uint8_t>> ipmiOemSetBootOrder( 1160 ipmi::Context::ptr ctx, std::vector<uint8_t> bootSeq) 1161 { 1162 size_t len = bootSeq.size(); 1163 1164 if (len != SIZE_BOOT_ORDER) 1165 { 1166 phosphor::logging::log<phosphor::logging::level::ERR>( 1167 "Invalid Boot order length received"); 1168 return ipmi::responseReqDataLenInvalid(); 1169 } 1170 1171 std::optional<size_t> hostId = findHost(ctx->hostIdx); 1172 1173 if (!hostId) 1174 { 1175 phosphor::logging::log<phosphor::logging::level::ERR>( 1176 "Invalid Host Id received"); 1177 return ipmi::responseInvalidCommand(); 1178 } 1179 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId); 1180 1181 ipmi::boot::setBootOrder(bootObjPath, bootSeq, hostName); 1182 1183 return ipmi::responseSuccess(bootSeq); 1184 } 1185 1186 //---------------------------------------------------------------------- 1187 // Get Boot Order (CMD_OEM_GET_BOOT_ORDER) 1188 //---------------------------------------------------------------------- 1189 ipmi::RspType<std::vector<uint8_t>> ipmiOemGetBootOrder(ipmi::Context::ptr ctx) 1190 { 1191 std::vector<uint8_t> bootSeq; 1192 1193 std::optional<size_t> hostId = findHost(ctx->hostIdx); 1194 1195 if (!hostId) 1196 { 1197 phosphor::logging::log<phosphor::logging::level::ERR>( 1198 "Invalid Host Id received"); 1199 return ipmi::responseInvalidCommand(); 1200 } 1201 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId); 1202 1203 ipmi::boot::getBootOrder(bootObjPath, bootSeq, hostName); 1204 1205 return ipmi::responseSuccess(bootSeq); 1206 } 1207 // Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO) 1208 //---------------------------------------------------------------------- 1209 ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t, ipmi_cmd_t, 1210 ipmi_request_t request, ipmi_response_t, 1211 ipmi_data_len_t data_len, ipmi_context_t) 1212 { 1213 machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request); 1214 uint8_t len = *data_len; 1215 1216 *data_len = 0; 1217 1218 if (len < sizeof(machineConfigInfo_t)) 1219 { 1220 phosphor::logging::log<phosphor::logging::level::ERR>( 1221 "Invalid machine configuration length received"); 1222 return ipmi::ccReqDataLenInvalid; 1223 } 1224 1225 if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*)) 1226 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN"; 1227 else 1228 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = 1229 chassisType[req->chassis_type]; 1230 1231 if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*)) 1232 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN"; 1233 else 1234 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type]; 1235 1236 oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt; 1237 oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt; 1238 oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt; 1239 oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt; 1240 1241 if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*)) 1242 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN"; 1243 else 1244 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type]; 1245 1246 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {}; 1247 int i = 0; 1248 if (req->pcie_card_loc & BIT_0) 1249 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1"; 1250 if (req->pcie_card_loc & BIT_1) 1251 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2"; 1252 if (req->pcie_card_loc & BIT_2) 1253 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3"; 1254 if (req->pcie_card_loc & BIT_3) 1255 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4"; 1256 1257 if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*)) 1258 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN"; 1259 else 1260 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = 1261 pcieType[req->slot1_pcie_type]; 1262 1263 if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*)) 1264 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN"; 1265 else 1266 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = 1267 pcieType[req->slot2_pcie_type]; 1268 1269 if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*)) 1270 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN"; 1271 else 1272 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = 1273 pcieType[req->slot3_pcie_type]; 1274 1275 if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*)) 1276 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN"; 1277 else 1278 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = 1279 pcieType[req->slot4_pcie_type]; 1280 1281 oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt; 1282 1283 flushOemData(); 1284 1285 return ipmi::ccSuccess; 1286 } 1287 1288 //---------------------------------------------------------------------- 1289 // Set POST start (CMD_OEM_SET_POST_START) 1290 //---------------------------------------------------------------------- 1291 ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1292 ipmi_response_t, ipmi_data_len_t data_len, 1293 ipmi_context_t) 1294 { 1295 phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event"); 1296 1297 /* Do nothing, return success */ 1298 *data_len = 0; 1299 return ipmi::ccSuccess; 1300 } 1301 1302 //---------------------------------------------------------------------- 1303 // Set POST End (CMD_OEM_SET_POST_END) 1304 //---------------------------------------------------------------------- 1305 ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1306 ipmi_response_t, ipmi_data_len_t data_len, 1307 ipmi_context_t) 1308 { 1309 struct timespec ts; 1310 1311 phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event"); 1312 1313 *data_len = 0; 1314 1315 // Timestamp post end time. 1316 clock_gettime(CLOCK_REALTIME, &ts); 1317 oemData[KEY_TS_SLED] = ts.tv_sec; 1318 flushOemData(); 1319 1320 // Sync time with system 1321 // TODO: Add code for syncing time 1322 1323 return ipmi::ccSuccess; 1324 } 1325 1326 //---------------------------------------------------------------------- 1327 // Set PPIN Info (CMD_OEM_SET_PPIN_INFO) 1328 //---------------------------------------------------------------------- 1329 // Inform BMC about PPIN data of 8 bytes for each CPU 1330 // 1331 // Request: 1332 // Byte 1:8 – CPU0 PPIN data 1333 // Optional: 1334 // Byte 9:16 – CPU1 PPIN data 1335 // 1336 // Response: 1337 // Byte 1 – Completion Code 1338 ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1339 ipmi_response_t, ipmi_data_len_t data_len, 1340 ipmi_context_t) 1341 { 1342 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1343 std::string ppinStr; 1344 int len; 1345 1346 if (*data_len > SIZE_CPU_PPIN * 2) 1347 len = SIZE_CPU_PPIN * 2; 1348 else 1349 len = *data_len; 1350 *data_len = 0; 1351 1352 ppinStr = bytesToStr(req, len); 1353 oemData[KEY_PPIN_INFO] = ppinStr.c_str(); 1354 flushOemData(); 1355 1356 return ipmi::ccSuccess; 1357 } 1358 1359 //---------------------------------------------------------------------- 1360 // Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER) 1361 //---------------------------------------------------------------------- 1362 ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1363 ipmi_response_t, ipmi_data_len_t data_len, 1364 ipmi_context_t) 1365 { 1366 /* Do nothing, return success */ 1367 *data_len = 0; 1368 return ipmi::ccSuccess; 1369 } 1370 1371 // Helper function to set guid at offset in EEPROM 1372 [[maybe_unused]] static int setGUID(off_t offset, uint8_t* guid) 1373 { 1374 int fd = -1; 1375 ssize_t len; 1376 int ret = 0; 1377 std::string eepromPath = FRU_EEPROM; 1378 1379 // find the eeprom path of MB FRU 1380 auto device = getMbFruDevice(); 1381 if (device) 1382 { 1383 auto [bus, address] = *device; 1384 std::stringstream ss; 1385 ss << "/sys/bus/i2c/devices/" << static_cast<int>(bus) << "-" 1386 << std::setw(4) << std::setfill('0') << std::hex 1387 << static_cast<int>(address) << "/eeprom"; 1388 eepromPath = ss.str(); 1389 } 1390 1391 errno = 0; 1392 1393 // Check if file is present 1394 if (access(eepromPath.c_str(), F_OK) == -1) 1395 { 1396 std::cerr << "Unable to access: " << eepromPath << std::endl; 1397 return errno; 1398 } 1399 1400 // Open the file 1401 fd = open(eepromPath.c_str(), O_WRONLY); 1402 if (fd == -1) 1403 { 1404 std::cerr << "Unable to open: " << eepromPath << std::endl; 1405 return errno; 1406 } 1407 1408 // seek to the offset 1409 lseek(fd, offset, SEEK_SET); 1410 1411 // Write bytes to location 1412 len = write(fd, guid, GUID_SIZE); 1413 if (len != GUID_SIZE) 1414 { 1415 phosphor::logging::log<phosphor::logging::level::ERR>( 1416 "GUID write data to EEPROM failed"); 1417 ret = errno; 1418 } 1419 1420 close(fd); 1421 return ret; 1422 } 1423 1424 //---------------------------------------------------------------------- 1425 // Set System GUID (CMD_OEM_SET_SYSTEM_GUID) 1426 //---------------------------------------------------------------------- 1427 #if BIC_ENABLED 1428 ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx, 1429 std::vector<uint8_t> reqData) 1430 { 1431 std::vector<uint8_t> respData; 1432 1433 if (reqData.size() != GUID_SIZE) // 16bytes 1434 { 1435 return ipmi::responseReqDataLenInvalid(); 1436 } 1437 1438 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2; 1439 1440 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData)) 1441 return ipmi::responseUnspecifiedError(); 1442 1443 return ipmi::responseSuccess(); 1444 } 1445 1446 #else 1447 ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t, ipmi_cmd_t, 1448 ipmi_request_t request, ipmi_response_t, 1449 ipmi_data_len_t data_len, ipmi_context_t) 1450 { 1451 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1452 1453 if (*data_len != GUID_SIZE) // 16bytes 1454 { 1455 *data_len = 0; 1456 return ipmi::ccReqDataLenInvalid; 1457 } 1458 1459 *data_len = 0; 1460 1461 if (setGUID(OFFSET_SYS_GUID, req)) 1462 { 1463 return ipmi::ccUnspecifiedError; 1464 } 1465 return ipmi::ccSuccess; 1466 } 1467 #endif 1468 1469 //---------------------------------------------------------------------- 1470 // Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO) 1471 //---------------------------------------------------------------------- 1472 ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1473 ipmi_response_t, ipmi_data_len_t data_len, 1474 ipmi_context_t) 1475 { 1476 /* Do nothing, return success */ 1477 *data_len = 0; 1478 return ipmi::ccSuccess; 1479 } 1480 1481 //---------------------------------------------------------------------- 1482 // Set PPR (CMD_OEM_SET_PPR) 1483 //---------------------------------------------------------------------- 1484 ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1485 ipmi_response_t, ipmi_data_len_t data_len, 1486 ipmi_context_t) 1487 { 1488 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1489 uint8_t pprCnt, pprAct, pprIndex; 1490 uint8_t selParam = req[0]; 1491 uint8_t len = *data_len; 1492 std::stringstream ss; 1493 std::string str; 1494 1495 *data_len = 0; 1496 1497 switch (selParam) 1498 { 1499 case PPR_ACTION: 1500 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) == 1501 oemData[KEY_PPR].end()) 1502 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 1503 1504 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1505 if (pprCnt == 0) 1506 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 1507 1508 pprAct = req[1]; 1509 /* Check if ppr is enabled or disabled */ 1510 if (!(pprAct & 0x80)) 1511 pprAct = 0; 1512 1513 oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct; 1514 break; 1515 case PPR_ROW_COUNT: 1516 if (req[1] > 100) 1517 return ipmi::ccParmOutOfRange; 1518 1519 oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1]; 1520 break; 1521 case PPR_ROW_ADDR: 1522 pprIndex = req[1]; 1523 if (pprIndex > 100) 1524 return ipmi::ccParmOutOfRange; 1525 1526 if (len < PPR_ROW_ADDR_LEN + 1) 1527 { 1528 phosphor::logging::log<phosphor::logging::level::ERR>( 1529 "Invalid PPR Row Address length received"); 1530 return ipmi::ccReqDataLenInvalid; 1531 } 1532 1533 ss << std::hex; 1534 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1535 1536 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex; 1537 1538 str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN); 1539 oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str(); 1540 break; 1541 case PPR_HISTORY_DATA: 1542 pprIndex = req[1]; 1543 if (pprIndex > 100) 1544 return ipmi::ccParmOutOfRange; 1545 1546 if (len < PPR_HST_DATA_LEN + 1) 1547 { 1548 phosphor::logging::log<phosphor::logging::level::ERR>( 1549 "Invalid PPR history data length received"); 1550 return ipmi::ccReqDataLenInvalid; 1551 } 1552 1553 ss << std::hex; 1554 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1555 1556 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex; 1557 1558 str = bytesToStr(&req[1], PPR_HST_DATA_LEN); 1559 oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str(); 1560 break; 1561 default: 1562 return ipmi::ccParmOutOfRange; 1563 break; 1564 } 1565 1566 flushOemData(); 1567 1568 return ipmi::ccSuccess; 1569 } 1570 1571 //---------------------------------------------------------------------- 1572 // Get PPR (CMD_OEM_GET_PPR) 1573 //---------------------------------------------------------------------- 1574 ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1575 ipmi_response_t response, ipmi_data_len_t data_len, 1576 ipmi_context_t) 1577 { 1578 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1579 uint8_t* res = reinterpret_cast<uint8_t*>(response); 1580 uint8_t pprCnt, pprIndex; 1581 uint8_t selParam = req[0]; 1582 std::stringstream ss; 1583 std::string str; 1584 1585 /* Any failure will return zero length data */ 1586 *data_len = 0; 1587 1588 switch (selParam) 1589 { 1590 case PPR_ACTION: 1591 res[0] = 0; 1592 *data_len = 1; 1593 1594 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) != 1595 oemData[KEY_PPR].end()) 1596 { 1597 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1598 if (pprCnt != 0) 1599 { 1600 if (oemData[KEY_PPR].find(KEY_PPR_ACTION) != 1601 oemData[KEY_PPR].end()) 1602 { 1603 res[0] = oemData[KEY_PPR][KEY_PPR_ACTION]; 1604 } 1605 } 1606 } 1607 break; 1608 case PPR_ROW_COUNT: 1609 res[0] = 0; 1610 *data_len = 1; 1611 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) != 1612 oemData[KEY_PPR].end()) 1613 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1614 break; 1615 case PPR_ROW_ADDR: 1616 pprIndex = req[1]; 1617 if (pprIndex > 100) 1618 return ipmi::ccParmOutOfRange; 1619 1620 ss << std::hex; 1621 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1622 1623 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end()) 1624 return ipmi::ccParmOutOfRange; 1625 1626 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) == 1627 oemData[KEY_PPR][ss.str()].end()) 1628 return ipmi::ccParmOutOfRange; 1629 1630 str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR]; 1631 *data_len = strToBytes(str, res); 1632 break; 1633 case PPR_HISTORY_DATA: 1634 pprIndex = req[1]; 1635 if (pprIndex > 100) 1636 return ipmi::ccParmOutOfRange; 1637 1638 ss << std::hex; 1639 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1640 1641 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end()) 1642 return ipmi::ccParmOutOfRange; 1643 1644 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) == 1645 oemData[KEY_PPR][ss.str()].end()) 1646 return ipmi::ccParmOutOfRange; 1647 1648 str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA]; 1649 *data_len = strToBytes(str, res); 1650 break; 1651 default: 1652 return ipmi::ccParmOutOfRange; 1653 break; 1654 } 1655 1656 return ipmi::ccSuccess; 1657 } 1658 1659 //---------------------------------------------------------------------- 1660 // Get FRU ID (CMD_OEM_GET_FRU_ID) 1661 //---------------------------------------------------------------------- 1662 // BIOS issues this command to retrieve the FRU ID using the bus and slave 1663 // address. FRU IDs are dynamic based on entity-manager probe orders so 1664 // this allows a look-up based on known data from the host to identify a 1665 // specific FRU. 1666 // 1667 // netfn 0x30, cmd 0x84 1668 // 1669 // Request: 1670 // - Byte 1: bus 1671 // - Byte 2: slave address 1672 // 1673 // Response: 1674 // - Byte 1 - Completion Code 1675 // - Byte 2 - FRU ID 1676 1677 ipmi_ret_t ipmiOemGetFruId(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1678 ipmi_response_t response, ipmi_data_len_t data_len, 1679 ipmi_context_t) 1680 { 1681 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1682 uint8_t* res = reinterpret_cast<uint8_t*>(response); 1683 auto bus = sdbusplus::bus::new_default(); 1684 1685 const uint32_t targetBus = req[0]; 1686 const uint32_t targetAddress = req[1]; 1687 *data_len = 1; 1688 1689 const std::string service = "xyz.openbmc_project.FruDevice"; 1690 const std::string rootPath = "/xyz/openbmc_project/FruDevice"; 1691 1692 auto method = bus.new_method_call(service.c_str(), "/", 1693 "org.freedesktop.DBus.ObjectManager", 1694 "GetManagedObjects"); 1695 1696 auto reply = bus.call(method); 1697 1698 using PropertyValue = std::variant<std::string, uint32_t, int32_t, bool>; 1699 1700 std::map<sdbusplus::message::object_path, 1701 std::map<std::string, std::map<std::string, PropertyValue>>> 1702 objects; 1703 1704 reply.read(objects); 1705 1706 int index = 0; 1707 bool found = false; 1708 1709 for (const auto& [path, interfaces] : objects) 1710 { 1711 if (path.str.find(rootPath) != 0) 1712 continue; 1713 1714 auto it = interfaces.find("xyz.openbmc_project.FruDevice"); 1715 if (it != interfaces.end()) 1716 { 1717 const auto& properties = it->second; 1718 1719 auto busIt = properties.find("BUS"); 1720 auto addrIt = properties.find("ADDRESS"); 1721 1722 if (busIt != properties.end() && addrIt != properties.end()) 1723 { 1724 try 1725 { 1726 uint32_t busValue = std::get<uint32_t>(busIt->second); 1727 uint32_t addrValue = std::get<uint32_t>(addrIt->second); 1728 1729 if (busValue == targetBus && addrValue == targetAddress) 1730 { 1731 std::cout 1732 << "Match found at index: " << index << std::endl; 1733 std::cout << "Path: " << path.str << std::endl; 1734 res[0] = index; 1735 found = true; 1736 break; 1737 } 1738 } 1739 catch (const std::bad_variant_access& e) 1740 { 1741 std::cerr << "️Unexpected property type at index " << index 1742 << std::endl; 1743 return -1; 1744 } 1745 } 1746 index++; 1747 } 1748 } 1749 1750 if (!found) 1751 { 1752 std::cout << "No matching FRU device found for BUS=" << targetBus 1753 << " and ADDRESS=" << targetAddress << std::endl; 1754 return -1; 1755 } 1756 1757 return ipmi::ccSuccess; 1758 } 1759 1760 /* FB OEM QC Commands */ 1761 1762 //---------------------------------------------------------------------- 1763 // Set Proc Info (CMD_OEM_Q_SET_PROC_INFO) 1764 //---------------------------------------------------------------------- 1765 //"Request: 1766 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first 1767 // Byte 4 – Processor Index, 0 base 1768 // Byte 5 – Parameter Selector 1769 // Byte 6..N – Configuration parameter data (see below for Parameters 1770 // of Processor Information) 1771 // Response: 1772 // Byte 1 – Completion code 1773 // 1774 // Parameter#1: (Processor Product Name) 1775 // 1776 // Byte 1..48 –Product name(ASCII code) 1777 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz 1778 // 1779 // Param#2: Processor Basic Information 1780 // Byte 1 – Core Number 1781 // Byte 2 – Thread Number (LSB) 1782 // Byte 3 – Thread Number (MSB) 1783 // Byte 4 – Processor frequency in MHz (LSB) 1784 // Byte 5 – Processor frequency in MHz (MSB) 1785 // Byte 6..7 – Revision 1786 // 1787 1788 ipmi::RspType<> ipmiOemQSetProcInfo( 1789 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex, 1790 uint8_t paramSel, std::vector<uint8_t> request) 1791 { 1792 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*); 1793 std::stringstream ss; 1794 std::string str; 1795 uint8_t len = request.size(); 1796 auto hostId = findHost(ctx->hostIdx); 1797 if (!hostId) 1798 { 1799 phosphor::logging::log<phosphor::logging::level::ERR>( 1800 "Invalid Host Id received"); 1801 return ipmi::responseInvalidCommand(); 1802 } 1803 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId); 1804 /* check for requested data params */ 1805 if (len < 5 || paramSel < 1 || paramSel >= numParam) 1806 { 1807 phosphor::logging::log<phosphor::logging::level::ERR>( 1808 "Invalid parameter received"); 1809 return ipmi::responseParmOutOfRange(); 1810 } 1811 ss << std::hex; 1812 ss << std::setw(2) << std::setfill('0') << (int)procIndex; 1813 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex; 1814 str = bytesToStr(request.data(), len); 1815 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str(); 1816 flushOemData(); 1817 return ipmi::responseSuccess(); 1818 } 1819 1820 //---------------------------------------------------------------------- 1821 // Get Proc Info (CMD_OEM_Q_GET_PROC_INFO) 1822 //---------------------------------------------------------------------- 1823 // Request: 1824 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first 1825 // Byte 4 – Processor Index, 0 base 1826 // Byte 5 – Parameter Selector 1827 // Response: 1828 // Byte 1 – Completion code 1829 // Byte 2..N – Configuration Parameter Data (see below for Parameters 1830 // of Processor Information) 1831 // 1832 // Parameter#1: (Processor Product Name) 1833 // 1834 // Byte 1..48 –Product name(ASCII code) 1835 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz 1836 // 1837 // Param#2: Processor Basic Information 1838 // Byte 1 – Core Number 1839 // Byte 2 – Thread Number (LSB) 1840 // Byte 3 – Thread Number (MSB) 1841 // Byte 4 – Processor frequency in MHz (LSB) 1842 // Byte 5 – Processor frequency in MHz (MSB) 1843 // Byte 6..7 – Revision 1844 // 1845 1846 ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetProcInfo( 1847 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex, 1848 uint8_t paramSel) 1849 { 1850 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*); 1851 std::stringstream ss; 1852 std::string str; 1853 uint8_t res[MAX_BUF]; 1854 auto hostId = findHost(ctx->hostIdx); 1855 if (!hostId) 1856 { 1857 phosphor::logging::log<phosphor::logging::level::ERR>( 1858 "Invalid Host Id received"); 1859 return ipmi::responseInvalidCommand(); 1860 } 1861 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId); 1862 if (paramSel < 1 || paramSel >= numParam) 1863 { 1864 phosphor::logging::log<phosphor::logging::level::ERR>( 1865 "Invalid parameter received"); 1866 return ipmi::responseParmOutOfRange(); 1867 } 1868 ss << std::hex; 1869 ss << std::setw(2) << std::setfill('0') << (int)procIndex; 1870 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end()) 1871 return ipmi::responseCommandNotAvailable(); 1872 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) == 1873 oemData[procInfo][ss.str()].end()) 1874 return ipmi::responseCommandNotAvailable(); 1875 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]]; 1876 int dataLen = strToBytes(str, res); 1877 std::vector<uint8_t> response(&res[0], &res[dataLen]); 1878 return ipmi::responseSuccess(response); 1879 } 1880 1881 //---------------------------------------------------------------------- 1882 // Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO) 1883 //---------------------------------------------------------------------- 1884 // Request: 1885 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first 1886 // Byte 4 – DIMM Index, 0 base 1887 // Byte 5 – Parameter Selector 1888 // Byte 6..N – Configuration parameter data (see below for Parameters 1889 // of DIMM Information) 1890 // Response: 1891 // Byte 1 – Completion code 1892 // 1893 // Param#1 (DIMM Location): 1894 // Byte 1 – DIMM Present 1895 // Byte 1 – DIMM Present 1896 // 01h – Present 1897 // FFh – Not Present 1898 // Byte 2 – Node Number, 0 base 1899 // Byte 3 – Channel Number , 0 base 1900 // Byte 4 – DIMM Number , 0 base 1901 // 1902 // Param#2 (DIMM Type): 1903 // Byte 1 – DIMM Type 1904 // Bit [7:6] 1905 // For DDR3 1906 // 00 – Normal Voltage (1.5V) 1907 // 01 – Ultra Low Voltage (1.25V) 1908 // 10 – Low Voltage (1.35V) 1909 // 11 – Reserved 1910 // For DDR4 1911 // 00 – Reserved 1912 // 01 – Reserved 1913 // 10 – Reserved 1914 // 11 – Normal Voltage (1.2V) 1915 // Bit [5:0] 1916 // 0x00 – SDRAM 1917 // 0x01 – DDR-1 RAM 1918 // 0x02 – Rambus 1919 // 0x03 – DDR-2 RAM 1920 // 0x04 – FBDIMM 1921 // 0x05 – DDR-3 RAM 1922 // 0x06 – DDR-4 RAM 1923 // 1924 // Param#3 (DIMM Speed): 1925 // Byte 1..2 – DIMM speed in MHz, LSB 1926 // Byte 3..6 – DIMM size in Mbytes, LSB 1927 // 1928 // Param#4 (Module Part Number): 1929 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C) 1930 // 1931 // Param#5 (Module Serial Number): 1932 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C) 1933 // 1934 // Param#6 (Module Manufacturer ID): 1935 // Byte 1 - Module Manufacturer ID, LSB 1936 // Byte 2 - Module Manufacturer ID, MSB 1937 // 1938 ipmi::RspType<> ipmiOemQSetDimmInfo( 1939 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex, 1940 uint8_t paramSel, std::vector<uint8_t> request) 1941 { 1942 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*); 1943 std::stringstream ss; 1944 std::string str; 1945 uint8_t len = request.size(); 1946 std::string dimmType; 1947 readDimmType(dimmType, dimmIndex); 1948 auto hostId = findHost(ctx->hostIdx); 1949 if (!hostId) 1950 { 1951 phosphor::logging::log<phosphor::logging::level::ERR>( 1952 "Invalid Host Id received"); 1953 return ipmi::responseInvalidCommand(); 1954 } 1955 1956 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId); 1957 1958 if (len < 3 || paramSel < 1 || paramSel >= numParam) 1959 { 1960 phosphor::logging::log<phosphor::logging::level::ERR>( 1961 "Invalid parameter received"); 1962 return ipmi::responseParmOutOfRange(); 1963 } 1964 1965 ss << std::hex; 1966 ss << (int)dimmIndex; 1967 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex; 1968 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType; 1969 str = bytesToStr(request.data(), len); 1970 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str(); 1971 flushOemData(); 1972 return ipmi::responseSuccess(); 1973 } 1974 1975 // Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO) 1976 //---------------------------------------------------------------------- 1977 // Request: 1978 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first 1979 // Byte 4 – DIMM Index, 0 base 1980 // Byte 5 – Parameter Selector 1981 // Byte 6..N – Configuration parameter data (see below for Parameters 1982 // of DIMM Information) 1983 // Response: 1984 // Byte 1 – Completion code 1985 // Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters 1986 // of DIMM Information) 1987 // 1988 // Param#1 (DIMM Location): 1989 // Byte 1 – DIMM Present 1990 // Byte 1 – DIMM Present 1991 // 01h – Present 1992 // FFh – Not Present 1993 // Byte 2 – Node Number, 0 base 1994 // Byte 3 – Channel Number , 0 base 1995 // Byte 4 – DIMM Number , 0 base 1996 // 1997 // Param#2 (DIMM Type): 1998 // Byte 1 – DIMM Type 1999 // Bit [7:6] 2000 // For DDR3 2001 // 00 – Normal Voltage (1.5V) 2002 // 01 – Ultra Low Voltage (1.25V) 2003 // 10 – Low Voltage (1.35V) 2004 // 11 – Reserved 2005 // For DDR4 2006 // 00 – Reserved 2007 // 01 – Reserved 2008 // 10 – Reserved 2009 // 11 – Normal Voltage (1.2V) 2010 // Bit [5:0] 2011 // 0x00 – SDRAM 2012 // 0x01 – DDR-1 RAM 2013 // 0x02 – Rambus 2014 // 0x03 – DDR-2 RAM 2015 // 0x04 – FBDIMM 2016 // 0x05 – DDR-3 RAM 2017 // 0x06 – DDR-4 RAM 2018 // 2019 // Param#3 (DIMM Speed): 2020 // Byte 1..2 – DIMM speed in MHz, LSB 2021 // Byte 3..6 – DIMM size in Mbytes, LSB 2022 // 2023 // Param#4 (Module Part Number): 2024 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C) 2025 // 2026 // Param#5 (Module Serial Number): 2027 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C) 2028 // 2029 // Param#6 (Module Manufacturer ID): 2030 // Byte 1 - Module Manufacturer ID, LSB 2031 // Byte 2 - Module Manufacturer ID, MSB 2032 // 2033 ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetDimmInfo( 2034 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex, 2035 uint8_t paramSel) 2036 { 2037 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*); 2038 uint8_t res[MAX_BUF]; 2039 std::stringstream ss; 2040 std::string str; 2041 std::string dimmType; 2042 readDimmType(dimmType, dimmIndex); 2043 auto hostId = findHost(ctx->hostIdx); 2044 if (!hostId) 2045 { 2046 phosphor::logging::log<phosphor::logging::level::ERR>( 2047 "Invalid Host Id received"); 2048 return ipmi::responseInvalidCommand(); 2049 } 2050 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId); 2051 2052 if (paramSel < 1 || paramSel >= numParam) 2053 { 2054 phosphor::logging::log<phosphor::logging::level::ERR>( 2055 "Invalid parameter received"); 2056 return ipmi::responseParmOutOfRange(); 2057 } 2058 ss << std::hex; 2059 ss << (int)dimmIndex; 2060 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType; 2061 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end()) 2062 return ipmi::responseCommandNotAvailable(); 2063 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) == 2064 oemData[dimmInfo][ss.str()].end()) 2065 return ipmi::responseCommandNotAvailable(); 2066 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]]; 2067 int data_length = strToBytes(str, res); 2068 std::vector<uint8_t> response(&res[0], &res[data_length]); 2069 return ipmi::responseSuccess(response); 2070 } 2071 2072 //---------------------------------------------------------------------- 2073 // Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO) 2074 //---------------------------------------------------------------------- 2075 // BIOS issue this command to provide HDD information to BMC. 2076 // 2077 // BIOS just can get information by standard ATA / SMART command for 2078 // OB SATA controller. 2079 // BIOS can get 2080 // 1. Serial Number 2081 // 2. Model Name 2082 // 3. HDD FW Version 2083 // 4. HDD Capacity 2084 // 5. HDD WWN 2085 // 2086 // Use Get HDD info Param #5 to know the MAX HDD info index. 2087 // 2088 // Request: 2089 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first 2090 // Byte 4 – 2091 // [7:4] Reserved 2092 // [3:0] HDD Controller Type 2093 // 0x00 – BIOS 2094 // 0x01 – Expander 2095 // 0x02 – LSI 2096 // Byte 5 – HDD Info Index, 0 base 2097 // Byte 6 – Parameter Selector 2098 // Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD 2099 // Information) 2100 // 2101 // Response: 2102 // Byte 1 – Completion Code 2103 // 2104 // Param#0 (HDD Location): 2105 // Byte 1 – Controller 2106 // [7:3] Device Number 2107 // [2:0] Function Number 2108 // For Intel C610 series (Wellsburg) 2109 // D31:F2 (0xFA) – SATA control 1 2110 // D31:F5 (0xFD) – SATA control 2 2111 // D17:F4 (0x8C) – sSata control 2112 // Byte 2 – Port Number 2113 // Byte 3 – Location (0xFF: No HDD Present) 2114 // BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param 2115 // #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if 2116 // the HDD present. BMC or other people who know the HDD location has 2117 // responsibility for update Location info 2118 // 2119 // Param#1 (Serial Number): 2120 // Bytes 1..33: HDD Serial Number 2121 // 2122 // Param#2 (Model Name): 2123 // Byte 1..33 – HDD Model Name 2124 // 2125 // Param#3 (HDD FW Version): 2126 // Byte 1..17 –HDD FW version 2127 // 2128 // Param#4 (Capacity): 2129 // Byte 1..4 –HDD Block Size, LSB 2130 // Byte 5..12 - HDD Block Number, LSB 2131 // HDD Capacity = HDD Block size * HDD BLock number (Unit Byte) 2132 // 2133 // Param#5 (Max HDD Quantity): 2134 // Byte 1 - Max HDD Quantity 2135 // Max supported port numbers in this PCH 2136 // 2137 // Param#6 (HDD Type) 2138 // Byte 1 – HDD Type 2139 // 0h – Reserved 2140 // 1h – SAS 2141 // 2h – SATA 2142 // 3h – PCIE SSD (NVME) 2143 // 2144 // Param#7 (HDD WWN) 2145 // Data 1...8: HDD World Wide Name, LSB 2146 // 2147 ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t, 2148 ipmi_request_t request, ipmi_response_t, 2149 ipmi_data_len_t data_len, ipmi_context_t) 2150 { 2151 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request); 2152 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*); 2153 uint8_t ctrlType = req->hddCtrlType & 0x0f; 2154 std::stringstream ss; 2155 std::string str; 2156 uint8_t len = *data_len; 2157 2158 *data_len = 0; 2159 2160 /* check for requested data params */ 2161 if (len < 6 || req->paramSel >= numParam || ctrlType > 2) 2162 { 2163 phosphor::logging::log<phosphor::logging::level::ERR>( 2164 "Invalid parameter received"); 2165 return ipmi::ccParmOutOfRange; 2166 } 2167 2168 len = len - 6; // Get Actual data length 2169 2170 ss << std::hex; 2171 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex; 2172 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType; 2173 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] = 2174 req->hddIndex; 2175 2176 str = bytesToStr(req->data, len); 2177 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()] 2178 [driveInfoKey[req->paramSel]] = str.c_str(); 2179 flushOemData(); 2180 2181 return ipmi::ccSuccess; 2182 } 2183 2184 //---------------------------------------------------------------------- 2185 // Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO) 2186 //---------------------------------------------------------------------- 2187 // BMC needs to check HDD presented or not first. If NOT presented, return 2188 // completion code 0xD5. 2189 // 2190 // Request: 2191 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first 2192 // Byte 4 – 2193 //[7:4] Reserved 2194 //[3:0] HDD Controller Type 2195 // 0x00 – BIOS 2196 // 0x01 – Expander 2197 // 0x02 – LSI 2198 // Byte 5 – HDD Index, 0 base 2199 // Byte 6 – Parameter Selector (See Above Set HDD Information) 2200 // Response: 2201 // Byte 1 – Completion Code 2202 // 0xD5 – Not support in current status (HDD Not Present) 2203 // Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD 2204 // Information) 2205 // 2206 ipmi_ret_t ipmiOemQGetDriveInfo( 2207 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, 2208 ipmi_data_len_t data_len, ipmi_context_t) 2209 { 2210 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request); 2211 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*); 2212 uint8_t* res = reinterpret_cast<uint8_t*>(response); 2213 uint8_t ctrlType = req->hddCtrlType & 0x0f; 2214 std::stringstream ss; 2215 std::string str; 2216 2217 *data_len = 0; 2218 2219 /* check for requested data params */ 2220 if (req->paramSel >= numParam || ctrlType > 2) 2221 { 2222 phosphor::logging::log<phosphor::logging::level::ERR>( 2223 "Invalid parameter received"); 2224 return ipmi::ccParmOutOfRange; 2225 } 2226 2227 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) == 2228 oemData[KEY_Q_DRIVE_INFO].end()) 2229 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2230 2231 ss << std::hex; 2232 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex; 2233 2234 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) == 2235 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].end()) 2236 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2237 2238 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find( 2239 driveInfoKey[req->paramSel]) == 2240 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].end()) 2241 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2242 2243 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()] 2244 [driveInfoKey[req->paramSel]]; 2245 *data_len = strToBytes(str, res); 2246 2247 return ipmi::ccSuccess; 2248 } 2249 2250 /* Helper function for sending DCMI commands to ME/BIC and 2251 * getting response back 2252 */ 2253 ipmi::RspType<std::vector<uint8_t>> sendDCMICmd( 2254 [[maybe_unused]] ipmi::Context::ptr ctx, [[maybe_unused]] uint8_t cmd, 2255 std::vector<uint8_t>& cmdData) 2256 { 2257 std::vector<uint8_t> respData; 2258 2259 #if BIC_ENABLED 2260 2261 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2; 2262 2263 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData)) 2264 { 2265 return ipmi::responseUnspecifiedError(); 2266 } 2267 2268 #else 2269 2270 /* Add group id as first byte to request for ME command */ 2271 cmdData.insert(cmdData.begin(), groupDCMI); 2272 2273 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData)) 2274 { 2275 return ipmi::responseUnspecifiedError(); 2276 } 2277 2278 /* Remove group id as first byte as it will be added by IPMID */ 2279 respData.erase(respData.begin()); 2280 2281 #endif 2282 2283 return ipmi::responseSuccess(std::move(respData)); 2284 } 2285 2286 /* DCMI Command handellers. */ 2287 2288 ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerReading( 2289 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2290 { 2291 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData); 2292 } 2293 2294 ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerLimit( 2295 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2296 { 2297 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData); 2298 } 2299 2300 ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMISetPowerLimit( 2301 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2302 { 2303 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData); 2304 } 2305 2306 ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIApplyPowerLimit( 2307 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2308 { 2309 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData); 2310 } 2311 2312 // Https Boot related functions 2313 ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsData( 2314 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2315 { 2316 if (reqData.size() < sizeof(HttpsDataReq)) 2317 return ipmi::responseReqDataLenInvalid(); 2318 2319 const auto* pReq = reinterpret_cast<const HttpsDataReq*>(reqData.data()); 2320 std::error_code ec; 2321 auto fileSize = std::filesystem::file_size(certPath, ec); 2322 if (ec) 2323 return ipmi::responseUnspecifiedError(); 2324 2325 if (pReq->offset >= fileSize) 2326 return ipmi::responseInvalidFieldRequest(); 2327 2328 std::ifstream file(certPath, std::ios::binary); 2329 if (!file) 2330 return ipmi::responseUnspecifiedError(); 2331 2332 auto readLen = std::min<uint16_t>(pReq->length, fileSize - pReq->offset); 2333 std::vector<uint8_t> resData(readLen + 1); 2334 resData[0] = readLen; 2335 file.seekg(pReq->offset); 2336 file.read(reinterpret_cast<char*>(resData.data() + 1), readLen); 2337 2338 return ipmi::responseSuccess(resData); 2339 } 2340 2341 ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsAttr( 2342 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2343 { 2344 if (reqData.size() < sizeof(HttpsBootAttr)) 2345 return ipmi::responseReqDataLenInvalid(); 2346 2347 std::vector<uint8_t> resData; 2348 2349 switch (static_cast<HttpsBootAttr>(reqData[0])) 2350 { 2351 case HttpsBootAttr::certSize: 2352 { 2353 std::error_code ec; 2354 auto fileSize = std::filesystem::file_size(certPath, ec); 2355 if (ec || fileSize > std::numeric_limits<uint16_t>::max()) 2356 return ipmi::responseUnspecifiedError(); 2357 2358 uint16_t size = static_cast<uint16_t>(fileSize); 2359 resData.resize(sizeof(uint16_t)); 2360 std::memcpy(resData.data(), &size, sizeof(uint16_t)); 2361 break; 2362 } 2363 case HttpsBootAttr::certCrc: 2364 { 2365 std::ifstream file(certPath, std::ios::binary); 2366 if (!file) 2367 return ipmi::responseUnspecifiedError(); 2368 2369 boost::crc_32_type result; 2370 char data[1024]; 2371 while (file.read(data, sizeof(data))) 2372 result.process_bytes(data, file.gcount()); 2373 if (file.gcount() > 0) 2374 result.process_bytes(data, file.gcount()); 2375 2376 uint32_t crc = result.checksum(); 2377 resData.resize(sizeof(uint32_t)); 2378 std::memcpy(resData.data(), &crc, sizeof(uint32_t)); 2379 break; 2380 } 2381 default: 2382 return ipmi::responseInvalidFieldRequest(); 2383 } 2384 2385 return ipmi::responseSuccess(resData); 2386 } 2387 2388 // OEM Crashdump related functions 2389 static ipmi_ret_t setDumpState(CrdState& currState, CrdState newState) 2390 { 2391 switch (newState) 2392 { 2393 case CrdState::waitData: 2394 if (currState == CrdState::packing) 2395 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2396 break; 2397 case CrdState::packing: 2398 if (currState != CrdState::waitData) 2399 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2400 break; 2401 case CrdState::free: 2402 break; 2403 default: 2404 return ipmi::ccUnspecifiedError; 2405 } 2406 currState = newState; 2407 2408 return ipmi::ccSuccess; 2409 } 2410 2411 static ipmi_ret_t handleMcaBank(const CrashDumpHdr& hdr, 2412 std::span<const uint8_t> data, 2413 CrdState& currState, std::stringstream& ss) 2414 { 2415 if (data.size() < sizeof(CrdMcaBank)) 2416 return ipmi::ccReqDataLenInvalid; 2417 2418 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2419 if (res) 2420 return res; 2421 2422 const auto* pBank = reinterpret_cast<const CrdMcaBank*>(data.data()); 2423 ss << std::format(" Bank ID : 0x{:02X}, Core ID : 0x{:02X}\n", 2424 hdr.bankHdr.bankId, hdr.bankHdr.coreId); 2425 ss << std::format(" MCA_CTRL : 0x{:016X}\n", pBank->mcaCtrl); 2426 ss << std::format(" MCA_STATUS : 0x{:016X}\n", pBank->mcaSts); 2427 ss << std::format(" MCA_ADDR : 0x{:016X}\n", pBank->mcaAddr); 2428 ss << std::format(" MCA_MISC0 : 0x{:016X}\n", pBank->mcaMisc0); 2429 ss << std::format(" MCA_CTRL_MASK : 0x{:016X}\n", pBank->mcaCtrlMask); 2430 ss << std::format(" MCA_CONFIG : 0x{:016X}\n", pBank->mcaConfig); 2431 ss << std::format(" MCA_IPID : 0x{:016X}\n", pBank->mcaIpid); 2432 ss << std::format(" MCA_SYND : 0x{:016X}\n", pBank->mcaSynd); 2433 ss << std::format(" MCA_DESTAT : 0x{:016X}\n", pBank->mcaDestat); 2434 ss << std::format(" MCA_DEADDR : 0x{:016X}\n", pBank->mcaDeaddr); 2435 ss << std::format(" MCA_MISC1 : 0x{:016X}\n", pBank->mcaMisc1); 2436 ss << "\n"; 2437 2438 return ipmi::ccSuccess; 2439 } 2440 2441 template <typename T> 2442 static ipmi_ret_t handleVirtualBank(std::span<const uint8_t> data, 2443 CrdState& currState, std::stringstream& ss) 2444 { 2445 if (data.size() < sizeof(T)) 2446 return ipmi::ccReqDataLenInvalid; 2447 2448 const auto* pBank = reinterpret_cast<const T*>(data.data()); 2449 2450 if (data.size() < sizeof(T) + sizeof(BankCorePair) * pBank->mcaCount) 2451 return ipmi::ccReqDataLenInvalid; 2452 2453 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2454 if (res) 2455 return res; 2456 2457 ss << " Virtual Bank\n"; 2458 ss << std::format(" S5_RESET_STATUS : 0x{:08X}\n", pBank->s5ResetSts); 2459 ss << std::format(" PM_BREAKEVENT : 0x{:08X}\n", pBank->breakevent); 2460 if constexpr (std::is_same_v<T, CrdVirtualBankV3>) 2461 { 2462 ss << std::format(" WARMCOLDRSTSTATUS : 0x{:08X}\n", pBank->rstSts); 2463 } 2464 ss << std::format(" PROCESSOR NUMBER : 0x{:04X}\n", pBank->procNum); 2465 ss << std::format(" APIC ID : 0x{:08X}\n", pBank->apicId); 2466 ss << std::format(" EAX : 0x{:08X}\n", pBank->eax); 2467 ss << std::format(" EBX : 0x{:08X}\n", pBank->ebx); 2468 ss << std::format(" ECX : 0x{:08X}\n", pBank->ecx); 2469 ss << std::format(" EDX : 0x{:08X}\n", pBank->edx); 2470 ss << " VALID LIST : "; 2471 for (size_t i = 0; i < pBank->mcaCount; i++) 2472 { 2473 ss << std::format("(0x{:02X},0x{:02X}) ", pBank->mcaList[i].bankId, 2474 pBank->mcaList[i].coreId); 2475 } 2476 ss << "\n\n"; 2477 2478 return ipmi::ccSuccess; 2479 } 2480 2481 static ipmi_ret_t handleCpuWdtBank(std::span<const uint8_t> data, 2482 CrdState& currState, std::stringstream& ss) 2483 { 2484 if (data.size() < sizeof(CrdCpuWdtBank)) 2485 return ipmi::ccReqDataLenInvalid; 2486 2487 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2488 if (res) 2489 return res; 2490 2491 const auto* pBank = reinterpret_cast<const CrdCpuWdtBank*>(data.data()); 2492 for (size_t i = 0; i < ccmNum; i++) 2493 { 2494 ss << std::format(" [CCM{}]\n", i); 2495 ss << std::format(" HwAssertStsHi : 0x{:08X}\n", 2496 pBank->hwAssertStsHi[i]); 2497 ss << std::format(" HwAssertStsLo : 0x{:08X}\n", 2498 pBank->hwAssertStsLo[i]); 2499 ss << std::format(" OrigWdtAddrLogHi : 0x{:08X}\n", 2500 pBank->origWdtAddrLogHi[i]); 2501 ss << std::format(" OrigWdtAddrLogLo : 0x{:08X}\n", 2502 pBank->origWdtAddrLogLo[i]); 2503 ss << std::format(" HwAssertMskHi : 0x{:08X}\n", 2504 pBank->hwAssertMskHi[i]); 2505 ss << std::format(" HwAssertMskLo : 0x{:08X}\n", 2506 pBank->hwAssertMskLo[i]); 2507 ss << std::format(" OrigWdtAddrLogStat : 0x{:08X}\n", 2508 pBank->origWdtAddrLogStat[i]); 2509 } 2510 ss << "\n"; 2511 2512 return ipmi::ccSuccess; 2513 } 2514 2515 template <size_t N> 2516 static ipmi_ret_t handleHwAssertBank(const char* name, 2517 std::span<const uint8_t> data, 2518 CrdState& currState, std::stringstream& ss) 2519 { 2520 if (data.size() < sizeof(CrdHwAssertBank<N>)) 2521 return ipmi::ccReqDataLenInvalid; 2522 2523 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2524 if (res) 2525 return res; 2526 2527 const CrdHwAssertBank<N>* pBank = 2528 reinterpret_cast<const CrdHwAssertBank<N>*>(data.data()); 2529 2530 for (size_t i = 0; i < N; i++) 2531 { 2532 ss << std::format(" [{}{}]\n", name, i); 2533 ss << std::format(" HwAssertStsHi : 0x{:08X}\n", 2534 pBank->hwAssertStsHi[i]); 2535 ss << std::format(" HwAssertStsLo : 0x{:08X}\n", 2536 pBank->hwAssertStsLo[i]); 2537 ss << std::format(" HwAssertMskHi : 0x{:08X}\n", 2538 pBank->hwAssertMskHi[i]); 2539 ss << std::format(" HwAssertMskLo : 0x{:08X}\n", 2540 pBank->hwAssertMskLo[i]); 2541 } 2542 ss << "\n"; 2543 2544 return ipmi::ccSuccess; 2545 } 2546 2547 static ipmi_ret_t handlePcieAerBank(std::span<const uint8_t> data, 2548 CrdState& currState, std::stringstream& ss) 2549 { 2550 if (data.size() < sizeof(CrdPcieAerBank)) 2551 return ipmi::ccReqDataLenInvalid; 2552 2553 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2554 if (res) 2555 return res; 2556 2557 const auto* pBank = reinterpret_cast<const CrdPcieAerBank*>(data.data()); 2558 ss << std::format(" [Bus{} Dev{} Fun{}]\n", pBank->bus, pBank->dev, 2559 pBank->fun); 2560 ss << std::format(" Command : 0x{:04X}\n", 2561 pBank->cmd); 2562 ss << std::format(" Status : 0x{:04X}\n", 2563 pBank->sts); 2564 ss << std::format(" Slot : 0x{:04X}\n", 2565 pBank->slot); 2566 ss << std::format(" Secondary Bus : 0x{:02X}\n", 2567 pBank->secondBus); 2568 ss << std::format(" Vendor ID : 0x{:04X}\n", 2569 pBank->vendorId); 2570 ss << std::format(" Device ID : 0x{:04X}\n", 2571 pBank->devId); 2572 ss << std::format(" Class Code : 0x{:02X}{:04X}\n", 2573 pBank->classCodeHi, pBank->classCodeLo); 2574 ss << std::format(" Bridge: Secondary Status : 0x{:04X}\n", 2575 pBank->secondSts); 2576 ss << std::format(" Bridge: Control : 0x{:04X}\n", 2577 pBank->ctrl); 2578 ss << std::format(" Uncorrectable Error Status : 0x{:08X}\n", 2579 pBank->uncorrErrSts); 2580 ss << std::format(" Uncorrectable Error Mask : 0x{:08X}\n", 2581 pBank->uncorrErrMsk); 2582 ss << std::format(" Uncorrectable Error Severity : 0x{:08X}\n", 2583 pBank->uncorrErrSeverity); 2584 ss << std::format(" Correctable Error Status : 0x{:08X}\n", 2585 pBank->corrErrSts); 2586 ss << std::format(" Correctable Error Mask : 0x{:08X}\n", 2587 pBank->corrErrMsk); 2588 ss << std::format(" Header Log DW0 : 0x{:08X}\n", 2589 pBank->hdrLogDw0); 2590 ss << std::format(" Header Log DW1 : 0x{:08X}\n", 2591 pBank->hdrLogDw1); 2592 ss << std::format(" Header Log DW2 : 0x{:08X}\n", 2593 pBank->hdrLogDw2); 2594 ss << std::format(" Header Log DW3 : 0x{:08X}\n", 2595 pBank->hdrLogDw3); 2596 ss << std::format(" Root Error Status : 0x{:08X}\n", 2597 pBank->rootErrSts); 2598 ss << std::format(" Correctable Error Source ID : 0x{:04X}\n", 2599 pBank->corrErrSrcId); 2600 ss << std::format(" Error Source ID : 0x{:04X}\n", 2601 pBank->errSrcId); 2602 ss << std::format(" Lane Error Status : 0x{:08X}\n", 2603 pBank->laneErrSts); 2604 ss << "\n"; 2605 2606 return ipmi::ccSuccess; 2607 } 2608 2609 static ipmi_ret_t handleWdtRegBank(std::span<const uint8_t> data, 2610 CrdState& currState, std::stringstream& ss) 2611 { 2612 if (data.size() < sizeof(CrdWdtRegBank)) 2613 return ipmi::ccReqDataLenInvalid; 2614 2615 const auto* pBank = reinterpret_cast<const CrdWdtRegBank*>(data.data()); 2616 if (data.size() < sizeof(CrdWdtRegBank) + sizeof(uint32_t) * pBank->count) 2617 return ipmi::ccReqDataLenInvalid; 2618 2619 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2620 if (res) 2621 return res; 2622 2623 ss << std::format(" [NBIO{}] {}\n", pBank->nbio, pBank->name); 2624 ss << std::format(" Address: 0x{:08X}\n", pBank->addr); 2625 ss << std::format(" Data Count: {}\n", pBank->count); 2626 ss << " Data:\n"; 2627 for (size_t i = 0; i < pBank->count; i++) 2628 { 2629 ss << std::format(" {}: 0x{:08X}\n", i, pBank->data[i]); 2630 } 2631 ss << "\n"; 2632 2633 return ipmi::ccSuccess; 2634 } 2635 2636 static ipmi_ret_t handleCrdHdrBank(std::span<const uint8_t> data, 2637 CrdState& currState, std::stringstream& ss) 2638 { 2639 if (data.size() < sizeof(CrdHdrBank)) 2640 return ipmi::ccReqDataLenInvalid; 2641 2642 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2643 if (res) 2644 return res; 2645 2646 const auto* pBank = reinterpret_cast<const CrdHdrBank*>(data.data()); 2647 ss << " Crashdump Header\n"; 2648 ss << std::format(" CPU PPIN : 0x{:016X}\n", pBank->ppin); 2649 ss << std::format(" UCODE VERSION : 0x{:08X}\n", pBank->ucodeVer); 2650 ss << std::format(" PMIO 80h : 0x{:08X}\n", pBank->pmio); 2651 ss << std::format( 2652 " BIT0 - SMN Parity/SMN Timeouts PSP/SMU Parity and ECC/SMN On-Package Link Error : {}\n", 2653 pBank->pmio & 0x1); 2654 ss << std::format(" BIT2 - PSP Parity and ECC : {}\n", 2655 (pBank->pmio & 0x4) >> 2); 2656 ss << std::format(" BIT3 - SMN Timeouts SMU : {}\n", 2657 (pBank->pmio & 0x8) >> 3); 2658 ss << std::format(" BIT4 - SMN Off-Package Link Packet Error : {}\n", 2659 (pBank->pmio & 0x10) >> 4); 2660 ss << "\n"; 2661 2662 return ipmi::ccSuccess; 2663 } 2664 2665 static std::string getFilename(const std::filesystem::path& dir, 2666 const std::string& prefix) 2667 { 2668 std::vector<int> indices; 2669 std::regex pattern(prefix + "(\\d+)\\.txt"); 2670 2671 for (const auto& entry : std::filesystem::directory_iterator(dir)) 2672 { 2673 std::string filename = entry.path().filename().string(); 2674 std::smatch match; 2675 if (std::regex_match(filename, match, pattern)) 2676 indices.push_back(std::stoi(match[1])); 2677 } 2678 2679 std::sort(indices.rbegin(), indices.rend()); 2680 while (indices.size() > 2) // keep 3 files, so remove if more than 2 2681 { 2682 std::filesystem::remove( 2683 dir / (prefix + std::to_string(indices.back()) + ".txt")); 2684 indices.pop_back(); 2685 } 2686 2687 int nextIndex = indices.empty() ? 1 : indices.front() + 1; 2688 return prefix + std::to_string(nextIndex) + ".txt"; 2689 } 2690 2691 static ipmi_ret_t handleCtrlBank(std::span<const uint8_t> data, 2692 CrdState& currState, std::stringstream& ss) 2693 { 2694 if (data.empty()) 2695 return ipmi::ccReqDataLenInvalid; 2696 2697 switch (static_cast<CrdCtrl>(data[0])) 2698 { 2699 case CrdCtrl::getState: 2700 break; 2701 case CrdCtrl::finish: 2702 { 2703 ipmi_ret_t res = setDumpState(currState, CrdState::packing); 2704 if (res) 2705 return res; 2706 2707 const std::filesystem::path dumpDir = "/var/lib/fb-ipmi-oem"; 2708 std::string filename = getFilename(dumpDir, "crashdump_"); 2709 std::ofstream outFile(dumpDir / filename); 2710 if (!outFile.is_open()) 2711 return ipmi::ccUnspecifiedError; 2712 2713 auto now = std::chrono::system_clock::to_time_t( 2714 std::chrono::system_clock::now()); 2715 outFile << "Crash Dump generated at: " 2716 << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S") 2717 << "\n\n"; 2718 outFile << ss.str(); 2719 outFile.close(); 2720 ss.str(""); 2721 ss.clear(); 2722 setDumpState(currState, CrdState::free); 2723 break; 2724 } 2725 default: 2726 return ccInvalidParam; 2727 } 2728 2729 return ipmi::ccSuccess; 2730 } 2731 2732 ipmi::RspType<std::vector<uint8_t>> ipmiOemCrashdump( 2733 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2734 { 2735 static CrdState dumpState = CrdState::free; 2736 static std::stringstream ss; 2737 2738 if (reqData.size() < sizeof(CrashDumpHdr)) 2739 return ipmi::responseReqDataLenInvalid(); 2740 2741 const auto* pHdr = reinterpret_cast<const CrashDumpHdr*>(reqData.data()); 2742 std::span<const uint8_t> bData{reqData.data() + sizeof(CrashDumpHdr), 2743 reqData.size() - sizeof(CrashDumpHdr)}; 2744 ipmi_ret_t res; 2745 2746 switch (pHdr->bankHdr.bankType) 2747 { 2748 case BankType::mca: 2749 res = handleMcaBank(*pHdr, bData, dumpState, ss); 2750 break; 2751 case BankType::virt: 2752 if (pHdr->bankHdr.version >= 3) 2753 { 2754 res = handleVirtualBank<CrdVirtualBankV3>(bData, dumpState, ss); 2755 break; 2756 } 2757 res = handleVirtualBank<CrdVirtualBankV2>(bData, dumpState, ss); 2758 break; 2759 case BankType::cpuWdt: 2760 res = handleCpuWdtBank(bData, dumpState, ss); 2761 break; 2762 case BankType::tcdx: 2763 res = handleHwAssertBank<tcdxNum>("TCDX", bData, dumpState, ss); 2764 break; 2765 case BankType::cake: 2766 res = handleHwAssertBank<cakeNum>("CAKE", bData, dumpState, ss); 2767 break; 2768 case BankType::pie0: 2769 res = handleHwAssertBank<pie0Num>("PIE", bData, dumpState, ss); 2770 break; 2771 case BankType::iom: 2772 res = handleHwAssertBank<iomNum>("IOM", bData, dumpState, ss); 2773 break; 2774 case BankType::ccix: 2775 res = handleHwAssertBank<ccixNum>("CCIX", bData, dumpState, ss); 2776 break; 2777 case BankType::cs: 2778 res = handleHwAssertBank<csNum>("CS", bData, dumpState, ss); 2779 break; 2780 case BankType::pcieAer: 2781 res = handlePcieAerBank(bData, dumpState, ss); 2782 break; 2783 case BankType::wdtReg: 2784 res = handleWdtRegBank(bData, dumpState, ss); 2785 break; 2786 case BankType::ctrl: 2787 res = handleCtrlBank(bData, dumpState, ss); 2788 if (res == ipmi::ccSuccess && 2789 static_cast<CrdCtrl>(bData[0]) == CrdCtrl::getState) 2790 { 2791 return ipmi::responseSuccess( 2792 std::vector<uint8_t>{static_cast<uint8_t>(dumpState)}); 2793 } 2794 break; 2795 case BankType::crdHdr: 2796 res = handleCrdHdrBank(bData, dumpState, ss); 2797 break; 2798 default: 2799 return ipmi::responseInvalidFieldRequest(); 2800 } 2801 2802 return ipmi::response(res); 2803 } 2804 2805 static void registerOEMFunctions(void) 2806 { 2807 /* Get OEM data from json file */ 2808 std::ifstream file(JSON_OEM_DATA_FILE); 2809 if (file) 2810 { 2811 try 2812 { 2813 file >> oemData; 2814 } 2815 // If parsing fails, initialize oemData as an empty JSON and 2816 // overwrite the file 2817 catch (const nlohmann::json::parse_error& e) 2818 { 2819 lg2::error("Error parsing JSON file: {ERROR}", "ERROR", e); 2820 oemData = nlohmann::json::object(); 2821 std::ofstream outFile(JSON_OEM_DATA_FILE, std::ofstream::trunc); 2822 outFile << oemData.dump(4); // Write empty JSON object to the file 2823 outFile.close(); 2824 } 2825 file.close(); 2826 } 2827 else 2828 { 2829 lg2::info("Failed to open JSON file."); 2830 } 2831 2832 lg2::info("Registering OEM commands."); 2833 2834 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO, 2835 NULL, ipmiOemDbgGetFrameInfo, 2836 PRIVILEGE_USER); // get debug frame info 2837 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, 2838 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL, 2839 ipmiOemDbgGetUpdFrames, 2840 PRIVILEGE_USER); // get debug updated frames 2841 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC, 2842 NULL, ipmiOemDbgGetPostDesc, 2843 PRIVILEGE_USER); // get debug post description 2844 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC, 2845 NULL, ipmiOemDbgGetGpioDesc, 2846 PRIVILEGE_USER); // get debug gpio description 2847 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA, 2848 NULL, ipmiOemDbgGetFrameData, 2849 PRIVILEGE_USER); // get debug frame data 2850 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL, 2851 NULL, ipmiOemDbgGetCtrlPanel, 2852 PRIVILEGE_USER); // get debug control panel 2853 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_DIMM_INFO, NULL, 2854 ipmiOemSetDimmInfo, 2855 PRIVILEGE_USER); // Set Dimm Info 2856 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_BOARD_ID, NULL, 2857 ipmiOemGetBoardID, 2858 PRIVILEGE_USER); // Get Board ID 2859 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne, 2860 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User, 2861 ipmiOemGet80PortRecord); // Get 80 Port Record 2862 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_MACHINE_CONFIG_INFO, 2863 NULL, ipmiOemSetMachineCfgInfo, 2864 PRIVILEGE_USER); // Set Machine Config Info 2865 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_START, NULL, 2866 ipmiOemSetPostStart, 2867 PRIVILEGE_USER); // Set POST start 2868 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_END, NULL, 2869 ipmiOemSetPostEnd, 2870 PRIVILEGE_USER); // Set POST End 2871 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPIN_INFO, NULL, 2872 ipmiOemSetPPINInfo, 2873 PRIVILEGE_USER); // Set PPIN Info 2874 #if BIC_ENABLED 2875 2876 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2877 ipmi::cmdSetSystemGuid, ipmi::Privilege::User, 2878 ipmiOemSetSystemGuid); 2879 #else 2880 2881 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_SYSTEM_GUID, NULL, 2882 ipmiOemSetSystemGuid, 2883 PRIVILEGE_USER); // Set System GUID 2884 #endif 2885 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_ADR_TRIGGER, NULL, 2886 ipmiOemSetAdrTrigger, 2887 PRIVILEGE_USER); // Set ADR Trigger 2888 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_BIOS_FLASH_INFO, NULL, 2889 ipmiOemSetBiosFlashInfo, 2890 PRIVILEGE_USER); // Set Bios Flash Info 2891 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPR, NULL, 2892 ipmiOemSetPpr, 2893 PRIVILEGE_USER); // Set PPR 2894 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_PPR, NULL, 2895 ipmiOemGetPpr, 2896 PRIVILEGE_USER); // Get PPR 2897 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_FRU_ID, NULL, 2898 ipmiOemGetFruId, 2899 PRIVILEGE_USER); // Get FRU ID 2900 /* FB OEM QC Commands */ 2901 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2902 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User, 2903 ipmiOemQSetProcInfo); // Set Proc Info 2904 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2905 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User, 2906 ipmiOemQGetProcInfo); // Get Proc Info 2907 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2908 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User, 2909 ipmiOemQSetDimmInfo); // Set Dimm Info 2910 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2911 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User, 2912 ipmiOemQGetDimmInfo); // Get Dimm Info 2913 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL, 2914 ipmiOemQSetDriveInfo, 2915 PRIVILEGE_USER); // Set Drive Info 2916 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL, 2917 ipmiOemQGetDriveInfo, 2918 PRIVILEGE_USER); // Get Drive Info 2919 2920 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */ 2921 ipmi::registerGroupHandler( 2922 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerReading, 2923 ipmi::Privilege::User, 2924 ipmiOemDCMIGetPowerReading); // Get Power Reading 2925 2926 ipmi::registerGroupHandler( 2927 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerLimit, 2928 ipmi::Privilege::User, 2929 ipmiOemDCMIGetPowerLimit); // Get Power Limit 2930 2931 ipmi::registerGroupHandler( 2932 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdSetPowerLimit, 2933 ipmi::Privilege::Operator, 2934 ipmiOemDCMISetPowerLimit); // Set Power Limit 2935 2936 ipmi::registerGroupHandler( 2937 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdActDeactivatePwrLimit, 2938 ipmi::Privilege::Operator, 2939 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit 2940 2941 /* FB OEM BOOT ORDER COMMANDS */ 2942 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2943 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User, 2944 ipmiOemGetBootOrder); // Get Boot Order 2945 2946 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2947 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User, 2948 ipmiOemSetBootOrder); // Set Boot Order 2949 2950 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2951 CMD_OEM_GET_HTTPS_BOOT_DATA, ipmi::Privilege::User, 2952 ipmiOemGetHttpsData); 2953 2954 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2955 CMD_OEM_GET_HTTPS_BOOT_ATTR, ipmi::Privilege::User, 2956 ipmiOemGetHttpsAttr); 2957 2958 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2959 CMD_OEM_CRASHDUMP, ipmi::Privilege::User, 2960 ipmiOemCrashdump); 2961 2962 return; 2963 } 2964 2965 } // namespace ipmi 2966