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 = 0; 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 auto objects = reply.unpack<std::map< 1701 sdbusplus::message::object_path, 1702 std::map<std::string, std::map<std::string, PropertyValue>>>>(); 1703 1704 int index = 0; 1705 bool found = false; 1706 1707 for (const auto& [path, interfaces] : objects) 1708 { 1709 if (path.str.find(rootPath) != 0) 1710 continue; 1711 1712 auto it = interfaces.find("xyz.openbmc_project.FruDevice"); 1713 if (it != interfaces.end()) 1714 { 1715 const auto& properties = it->second; 1716 1717 auto busIt = properties.find("BUS"); 1718 auto addrIt = properties.find("ADDRESS"); 1719 1720 if (busIt != properties.end() && addrIt != properties.end()) 1721 { 1722 try 1723 { 1724 uint32_t busValue = std::get<uint32_t>(busIt->second); 1725 uint32_t addrValue = std::get<uint32_t>(addrIt->second); 1726 1727 if (busValue == targetBus && addrValue == targetAddress) 1728 { 1729 std::cout 1730 << "Match found at index: " << index << std::endl; 1731 std::cout << "Path: " << path.str << std::endl; 1732 res[0] = index; 1733 found = true; 1734 break; 1735 } 1736 } 1737 catch (const std::bad_variant_access& e) 1738 { 1739 std::cerr << "️Unexpected property type at index " << index 1740 << std::endl; 1741 return -1; 1742 } 1743 } 1744 index++; 1745 } 1746 } 1747 1748 if (!found) 1749 { 1750 std::cout << "No matching FRU device found for BUS=" << targetBus 1751 << " and ADDRESS=" << targetAddress << std::endl; 1752 return -1; 1753 } 1754 1755 return ipmi::ccSuccess; 1756 } 1757 1758 /* FB OEM QC Commands */ 1759 1760 //---------------------------------------------------------------------- 1761 // Set Proc Info (CMD_OEM_Q_SET_PROC_INFO) 1762 //---------------------------------------------------------------------- 1763 //"Request: 1764 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first 1765 // Byte 4 – Processor Index, 0 base 1766 // Byte 5 – Parameter Selector 1767 // Byte 6..N – Configuration parameter data (see below for Parameters 1768 // of Processor Information) 1769 // Response: 1770 // Byte 1 – Completion code 1771 // 1772 // Parameter#1: (Processor Product Name) 1773 // 1774 // Byte 1..48 –Product name(ASCII code) 1775 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz 1776 // 1777 // Param#2: Processor Basic Information 1778 // Byte 1 – Core Number 1779 // Byte 2 – Thread Number (LSB) 1780 // Byte 3 – Thread Number (MSB) 1781 // Byte 4 – Processor frequency in MHz (LSB) 1782 // Byte 5 – Processor frequency in MHz (MSB) 1783 // Byte 6..7 – Revision 1784 // 1785 1786 ipmi::RspType<> ipmiOemQSetProcInfo( 1787 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex, 1788 uint8_t paramSel, std::vector<uint8_t> request) 1789 { 1790 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*); 1791 std::stringstream ss; 1792 std::string str; 1793 uint8_t len = request.size(); 1794 auto hostId = findHost(ctx->hostIdx); 1795 if (!hostId) 1796 { 1797 phosphor::logging::log<phosphor::logging::level::ERR>( 1798 "Invalid Host Id received"); 1799 return ipmi::responseInvalidCommand(); 1800 } 1801 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId); 1802 /* check for requested data params */ 1803 if (len < 5 || paramSel < 1 || paramSel >= numParam) 1804 { 1805 phosphor::logging::log<phosphor::logging::level::ERR>( 1806 "Invalid parameter received"); 1807 return ipmi::responseParmOutOfRange(); 1808 } 1809 ss << std::hex; 1810 ss << std::setw(2) << std::setfill('0') << (int)procIndex; 1811 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex; 1812 str = bytesToStr(request.data(), len); 1813 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str(); 1814 flushOemData(); 1815 return ipmi::responseSuccess(); 1816 } 1817 1818 //---------------------------------------------------------------------- 1819 // Get Proc Info (CMD_OEM_Q_GET_PROC_INFO) 1820 //---------------------------------------------------------------------- 1821 // Request: 1822 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first 1823 // Byte 4 – Processor Index, 0 base 1824 // Byte 5 – Parameter Selector 1825 // Response: 1826 // Byte 1 – Completion code 1827 // Byte 2..N – Configuration Parameter Data (see below for Parameters 1828 // of Processor Information) 1829 // 1830 // Parameter#1: (Processor Product Name) 1831 // 1832 // Byte 1..48 –Product name(ASCII code) 1833 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz 1834 // 1835 // Param#2: Processor Basic Information 1836 // Byte 1 – Core Number 1837 // Byte 2 – Thread Number (LSB) 1838 // Byte 3 – Thread Number (MSB) 1839 // Byte 4 – Processor frequency in MHz (LSB) 1840 // Byte 5 – Processor frequency in MHz (MSB) 1841 // Byte 6..7 – Revision 1842 // 1843 1844 ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetProcInfo( 1845 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex, 1846 uint8_t paramSel) 1847 { 1848 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*); 1849 std::stringstream ss; 1850 std::string str; 1851 uint8_t res[MAX_BUF]; 1852 auto hostId = findHost(ctx->hostIdx); 1853 if (!hostId) 1854 { 1855 phosphor::logging::log<phosphor::logging::level::ERR>( 1856 "Invalid Host Id received"); 1857 return ipmi::responseInvalidCommand(); 1858 } 1859 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId); 1860 if (paramSel < 1 || paramSel >= numParam) 1861 { 1862 phosphor::logging::log<phosphor::logging::level::ERR>( 1863 "Invalid parameter received"); 1864 return ipmi::responseParmOutOfRange(); 1865 } 1866 ss << std::hex; 1867 ss << std::setw(2) << std::setfill('0') << (int)procIndex; 1868 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end()) 1869 return ipmi::responseCommandNotAvailable(); 1870 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) == 1871 oemData[procInfo][ss.str()].end()) 1872 return ipmi::responseCommandNotAvailable(); 1873 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]]; 1874 int dataLen = strToBytes(str, res); 1875 std::vector<uint8_t> response(&res[0], &res[dataLen]); 1876 return ipmi::responseSuccess(response); 1877 } 1878 1879 //---------------------------------------------------------------------- 1880 // Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO) 1881 //---------------------------------------------------------------------- 1882 // Request: 1883 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first 1884 // Byte 4 – DIMM Index, 0 base 1885 // Byte 5 – Parameter Selector 1886 // Byte 6..N – Configuration parameter data (see below for Parameters 1887 // of DIMM Information) 1888 // Response: 1889 // Byte 1 – Completion code 1890 // 1891 // Param#1 (DIMM Location): 1892 // Byte 1 – DIMM Present 1893 // Byte 1 – DIMM Present 1894 // 01h – Present 1895 // FFh – Not Present 1896 // Byte 2 – Node Number, 0 base 1897 // Byte 3 – Channel Number , 0 base 1898 // Byte 4 – DIMM Number , 0 base 1899 // 1900 // Param#2 (DIMM Type): 1901 // Byte 1 – DIMM Type 1902 // Bit [7:6] 1903 // For DDR3 1904 // 00 – Normal Voltage (1.5V) 1905 // 01 – Ultra Low Voltage (1.25V) 1906 // 10 – Low Voltage (1.35V) 1907 // 11 – Reserved 1908 // For DDR4 1909 // 00 – Reserved 1910 // 01 – Reserved 1911 // 10 – Reserved 1912 // 11 – Normal Voltage (1.2V) 1913 // Bit [5:0] 1914 // 0x00 – SDRAM 1915 // 0x01 – DDR-1 RAM 1916 // 0x02 – Rambus 1917 // 0x03 – DDR-2 RAM 1918 // 0x04 – FBDIMM 1919 // 0x05 – DDR-3 RAM 1920 // 0x06 – DDR-4 RAM 1921 // 1922 // Param#3 (DIMM Speed): 1923 // Byte 1..2 – DIMM speed in MHz, LSB 1924 // Byte 3..6 – DIMM size in Mbytes, LSB 1925 // 1926 // Param#4 (Module Part Number): 1927 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C) 1928 // 1929 // Param#5 (Module Serial Number): 1930 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C) 1931 // 1932 // Param#6 (Module Manufacturer ID): 1933 // Byte 1 - Module Manufacturer ID, LSB 1934 // Byte 2 - Module Manufacturer ID, MSB 1935 // 1936 ipmi::RspType<> ipmiOemQSetDimmInfo( 1937 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex, 1938 uint8_t paramSel, std::vector<uint8_t> request) 1939 { 1940 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*); 1941 std::stringstream ss; 1942 std::string str; 1943 uint8_t len = request.size(); 1944 std::string dimmType; 1945 readDimmType(dimmType, dimmIndex); 1946 auto hostId = findHost(ctx->hostIdx); 1947 if (!hostId) 1948 { 1949 phosphor::logging::log<phosphor::logging::level::ERR>( 1950 "Invalid Host Id received"); 1951 return ipmi::responseInvalidCommand(); 1952 } 1953 1954 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId); 1955 1956 if (len < 3 || paramSel < 1 || paramSel >= numParam) 1957 { 1958 phosphor::logging::log<phosphor::logging::level::ERR>( 1959 "Invalid parameter received"); 1960 return ipmi::responseParmOutOfRange(); 1961 } 1962 1963 ss << std::hex; 1964 ss << (int)dimmIndex; 1965 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex; 1966 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType; 1967 str = bytesToStr(request.data(), len); 1968 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str(); 1969 flushOemData(); 1970 return ipmi::responseSuccess(); 1971 } 1972 1973 // Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO) 1974 //---------------------------------------------------------------------- 1975 // Request: 1976 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first 1977 // Byte 4 – DIMM Index, 0 base 1978 // Byte 5 – Parameter Selector 1979 // Byte 6..N – Configuration parameter data (see below for Parameters 1980 // of DIMM Information) 1981 // Response: 1982 // Byte 1 – Completion code 1983 // Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters 1984 // of DIMM Information) 1985 // 1986 // Param#1 (DIMM Location): 1987 // Byte 1 – DIMM Present 1988 // Byte 1 – DIMM Present 1989 // 01h – Present 1990 // FFh – Not Present 1991 // Byte 2 – Node Number, 0 base 1992 // Byte 3 – Channel Number , 0 base 1993 // Byte 4 – DIMM Number , 0 base 1994 // 1995 // Param#2 (DIMM Type): 1996 // Byte 1 – DIMM Type 1997 // Bit [7:6] 1998 // For DDR3 1999 // 00 – Normal Voltage (1.5V) 2000 // 01 – Ultra Low Voltage (1.25V) 2001 // 10 – Low Voltage (1.35V) 2002 // 11 – Reserved 2003 // For DDR4 2004 // 00 – Reserved 2005 // 01 – Reserved 2006 // 10 – Reserved 2007 // 11 – Normal Voltage (1.2V) 2008 // Bit [5:0] 2009 // 0x00 – SDRAM 2010 // 0x01 – DDR-1 RAM 2011 // 0x02 – Rambus 2012 // 0x03 – DDR-2 RAM 2013 // 0x04 – FBDIMM 2014 // 0x05 – DDR-3 RAM 2015 // 0x06 – DDR-4 RAM 2016 // 2017 // Param#3 (DIMM Speed): 2018 // Byte 1..2 – DIMM speed in MHz, LSB 2019 // Byte 3..6 – DIMM size in Mbytes, LSB 2020 // 2021 // Param#4 (Module Part Number): 2022 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C) 2023 // 2024 // Param#5 (Module Serial Number): 2025 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C) 2026 // 2027 // Param#6 (Module Manufacturer ID): 2028 // Byte 1 - Module Manufacturer ID, LSB 2029 // Byte 2 - Module Manufacturer ID, MSB 2030 // 2031 ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetDimmInfo( 2032 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex, 2033 uint8_t paramSel) 2034 { 2035 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*); 2036 uint8_t res[MAX_BUF]; 2037 std::stringstream ss; 2038 std::string str; 2039 std::string dimmType; 2040 readDimmType(dimmType, dimmIndex); 2041 auto hostId = findHost(ctx->hostIdx); 2042 if (!hostId) 2043 { 2044 phosphor::logging::log<phosphor::logging::level::ERR>( 2045 "Invalid Host Id received"); 2046 return ipmi::responseInvalidCommand(); 2047 } 2048 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId); 2049 2050 if (paramSel < 1 || paramSel >= numParam) 2051 { 2052 phosphor::logging::log<phosphor::logging::level::ERR>( 2053 "Invalid parameter received"); 2054 return ipmi::responseParmOutOfRange(); 2055 } 2056 ss << std::hex; 2057 ss << (int)dimmIndex; 2058 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType; 2059 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end()) 2060 return ipmi::responseCommandNotAvailable(); 2061 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) == 2062 oemData[dimmInfo][ss.str()].end()) 2063 return ipmi::responseCommandNotAvailable(); 2064 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]]; 2065 int data_length = strToBytes(str, res); 2066 std::vector<uint8_t> response(&res[0], &res[data_length]); 2067 return ipmi::responseSuccess(response); 2068 } 2069 2070 //---------------------------------------------------------------------- 2071 // Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO) 2072 //---------------------------------------------------------------------- 2073 // BIOS issue this command to provide HDD information to BMC. 2074 // 2075 // BIOS just can get information by standard ATA / SMART command for 2076 // OB SATA controller. 2077 // BIOS can get 2078 // 1. Serial Number 2079 // 2. Model Name 2080 // 3. HDD FW Version 2081 // 4. HDD Capacity 2082 // 5. HDD WWN 2083 // 2084 // Use Get HDD info Param #5 to know the MAX HDD info index. 2085 // 2086 // Request: 2087 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first 2088 // Byte 4 – 2089 // [7:4] Reserved 2090 // [3:0] HDD Controller Type 2091 // 0x00 – BIOS 2092 // 0x01 – Expander 2093 // 0x02 – LSI 2094 // Byte 5 – HDD Info Index, 0 base 2095 // Byte 6 – Parameter Selector 2096 // Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD 2097 // Information) 2098 // 2099 // Response: 2100 // Byte 1 – Completion Code 2101 // 2102 // Param#0 (HDD Location): 2103 // Byte 1 – Controller 2104 // [7:3] Device Number 2105 // [2:0] Function Number 2106 // For Intel C610 series (Wellsburg) 2107 // D31:F2 (0xFA) – SATA control 1 2108 // D31:F5 (0xFD) – SATA control 2 2109 // D17:F4 (0x8C) – sSata control 2110 // Byte 2 – Port Number 2111 // Byte 3 – Location (0xFF: No HDD Present) 2112 // BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param 2113 // #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if 2114 // the HDD present. BMC or other people who know the HDD location has 2115 // responsibility for update Location info 2116 // 2117 // Param#1 (Serial Number): 2118 // Bytes 1..33: HDD Serial Number 2119 // 2120 // Param#2 (Model Name): 2121 // Byte 1..33 – HDD Model Name 2122 // 2123 // Param#3 (HDD FW Version): 2124 // Byte 1..17 –HDD FW version 2125 // 2126 // Param#4 (Capacity): 2127 // Byte 1..4 –HDD Block Size, LSB 2128 // Byte 5..12 - HDD Block Number, LSB 2129 // HDD Capacity = HDD Block size * HDD BLock number (Unit Byte) 2130 // 2131 // Param#5 (Max HDD Quantity): 2132 // Byte 1 - Max HDD Quantity 2133 // Max supported port numbers in this PCH 2134 // 2135 // Param#6 (HDD Type) 2136 // Byte 1 – HDD Type 2137 // 0h – Reserved 2138 // 1h – SAS 2139 // 2h – SATA 2140 // 3h – PCIE SSD (NVME) 2141 // 2142 // Param#7 (HDD WWN) 2143 // Data 1...8: HDD World Wide Name, LSB 2144 // 2145 ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t, 2146 ipmi_request_t request, ipmi_response_t, 2147 ipmi_data_len_t data_len, ipmi_context_t) 2148 { 2149 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request); 2150 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*); 2151 uint8_t ctrlType = req->hddCtrlType & 0x0f; 2152 std::stringstream ss; 2153 std::string str; 2154 uint8_t len = *data_len; 2155 2156 *data_len = 0; 2157 2158 /* check for requested data params */ 2159 if (len < 6 || req->paramSel >= numParam || ctrlType > 2) 2160 { 2161 phosphor::logging::log<phosphor::logging::level::ERR>( 2162 "Invalid parameter received"); 2163 return ipmi::ccParmOutOfRange; 2164 } 2165 2166 len = len - 6; // Get Actual data length 2167 2168 ss << std::hex; 2169 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex; 2170 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType; 2171 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] = 2172 req->hddIndex; 2173 2174 str = bytesToStr(req->data, len); 2175 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()] 2176 [driveInfoKey[req->paramSel]] = str.c_str(); 2177 flushOemData(); 2178 2179 return ipmi::ccSuccess; 2180 } 2181 2182 //---------------------------------------------------------------------- 2183 // Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO) 2184 //---------------------------------------------------------------------- 2185 // BMC needs to check HDD presented or not first. If NOT presented, return 2186 // completion code 0xD5. 2187 // 2188 // Request: 2189 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first 2190 // Byte 4 – 2191 //[7:4] Reserved 2192 //[3:0] HDD Controller Type 2193 // 0x00 – BIOS 2194 // 0x01 – Expander 2195 // 0x02 – LSI 2196 // Byte 5 – HDD Index, 0 base 2197 // Byte 6 – Parameter Selector (See Above Set HDD Information) 2198 // Response: 2199 // Byte 1 – Completion Code 2200 // 0xD5 – Not support in current status (HDD Not Present) 2201 // Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD 2202 // Information) 2203 // 2204 ipmi_ret_t ipmiOemQGetDriveInfo( 2205 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, 2206 ipmi_data_len_t data_len, ipmi_context_t) 2207 { 2208 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request); 2209 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*); 2210 uint8_t* res = reinterpret_cast<uint8_t*>(response); 2211 uint8_t ctrlType = req->hddCtrlType & 0x0f; 2212 std::stringstream ss; 2213 std::string str; 2214 2215 *data_len = 0; 2216 2217 /* check for requested data params */ 2218 if (req->paramSel >= numParam || ctrlType > 2) 2219 { 2220 phosphor::logging::log<phosphor::logging::level::ERR>( 2221 "Invalid parameter received"); 2222 return ipmi::ccParmOutOfRange; 2223 } 2224 2225 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) == 2226 oemData[KEY_Q_DRIVE_INFO].end()) 2227 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2228 2229 ss << std::hex; 2230 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex; 2231 2232 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) == 2233 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].end()) 2234 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2235 2236 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find( 2237 driveInfoKey[req->paramSel]) == 2238 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].end()) 2239 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2240 2241 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()] 2242 [driveInfoKey[req->paramSel]]; 2243 *data_len = strToBytes(str, res); 2244 2245 return ipmi::ccSuccess; 2246 } 2247 2248 /* Helper function for sending DCMI commands to ME/BIC and 2249 * getting response back 2250 */ 2251 ipmi::RspType<std::vector<uint8_t>> sendDCMICmd( 2252 [[maybe_unused]] ipmi::Context::ptr ctx, [[maybe_unused]] uint8_t cmd, 2253 std::vector<uint8_t>& cmdData) 2254 { 2255 std::vector<uint8_t> respData; 2256 2257 #if BIC_ENABLED 2258 2259 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2; 2260 2261 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData)) 2262 { 2263 return ipmi::responseUnspecifiedError(); 2264 } 2265 2266 #else 2267 2268 /* Add group id as first byte to request for ME command */ 2269 cmdData.insert(cmdData.begin(), groupDCMI); 2270 2271 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData)) 2272 { 2273 return ipmi::responseUnspecifiedError(); 2274 } 2275 2276 /* Remove group id as first byte as it will be added by IPMID */ 2277 respData.erase(respData.begin()); 2278 2279 #endif 2280 2281 return ipmi::responseSuccess(std::move(respData)); 2282 } 2283 2284 /* DCMI Command handellers. */ 2285 2286 ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerReading( 2287 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2288 { 2289 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData); 2290 } 2291 2292 ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerLimit( 2293 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2294 { 2295 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData); 2296 } 2297 2298 ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMISetPowerLimit( 2299 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2300 { 2301 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData); 2302 } 2303 2304 ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIApplyPowerLimit( 2305 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2306 { 2307 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData); 2308 } 2309 2310 // Https Boot related functions 2311 ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsData( 2312 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2313 { 2314 if (reqData.size() < sizeof(HttpsDataReq)) 2315 return ipmi::responseReqDataLenInvalid(); 2316 2317 const auto* pReq = reinterpret_cast<const HttpsDataReq*>(reqData.data()); 2318 std::error_code ec; 2319 auto fileSize = std::filesystem::file_size(certPath, ec); 2320 if (ec) 2321 return ipmi::responseUnspecifiedError(); 2322 2323 if (pReq->offset >= fileSize) 2324 return ipmi::responseInvalidFieldRequest(); 2325 2326 std::ifstream file(certPath, std::ios::binary); 2327 if (!file) 2328 return ipmi::responseUnspecifiedError(); 2329 2330 auto readLen = std::min<uint16_t>(pReq->length, fileSize - pReq->offset); 2331 std::vector<uint8_t> resData(readLen + 1); 2332 resData[0] = readLen; 2333 file.seekg(pReq->offset); 2334 file.read(reinterpret_cast<char*>(resData.data() + 1), readLen); 2335 2336 return ipmi::responseSuccess(resData); 2337 } 2338 2339 ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsAttr( 2340 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2341 { 2342 if (reqData.size() < sizeof(HttpsBootAttr)) 2343 return ipmi::responseReqDataLenInvalid(); 2344 2345 std::vector<uint8_t> resData; 2346 2347 switch (static_cast<HttpsBootAttr>(reqData[0])) 2348 { 2349 case HttpsBootAttr::certSize: 2350 { 2351 std::error_code ec; 2352 auto fileSize = std::filesystem::file_size(certPath, ec); 2353 if (ec || fileSize > std::numeric_limits<uint16_t>::max()) 2354 return ipmi::responseUnspecifiedError(); 2355 2356 uint16_t size = static_cast<uint16_t>(fileSize); 2357 resData.resize(sizeof(uint16_t)); 2358 std::memcpy(resData.data(), &size, sizeof(uint16_t)); 2359 break; 2360 } 2361 case HttpsBootAttr::certCrc: 2362 { 2363 std::ifstream file(certPath, std::ios::binary); 2364 if (!file) 2365 return ipmi::responseUnspecifiedError(); 2366 2367 boost::crc_32_type result; 2368 char data[1024]; 2369 while (file.read(data, sizeof(data))) 2370 result.process_bytes(data, file.gcount()); 2371 if (file.gcount() > 0) 2372 result.process_bytes(data, file.gcount()); 2373 2374 uint32_t crc = result.checksum(); 2375 resData.resize(sizeof(uint32_t)); 2376 std::memcpy(resData.data(), &crc, sizeof(uint32_t)); 2377 break; 2378 } 2379 default: 2380 return ipmi::responseInvalidFieldRequest(); 2381 } 2382 2383 return ipmi::responseSuccess(resData); 2384 } 2385 2386 // OEM Crashdump related functions 2387 static ipmi_ret_t setDumpState(CrdState& currState, CrdState newState) 2388 { 2389 switch (newState) 2390 { 2391 case CrdState::waitData: 2392 if (currState == CrdState::packing) 2393 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2394 break; 2395 case CrdState::packing: 2396 if (currState != CrdState::waitData) 2397 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2398 break; 2399 case CrdState::free: 2400 break; 2401 default: 2402 return ipmi::ccUnspecifiedError; 2403 } 2404 currState = newState; 2405 2406 return ipmi::ccSuccess; 2407 } 2408 2409 static ipmi_ret_t handleMcaBank(const CrashDumpHdr& hdr, 2410 std::span<const uint8_t> data, 2411 CrdState& currState, std::stringstream& ss) 2412 { 2413 if (data.size() < sizeof(CrdMcaBank)) 2414 return ipmi::ccReqDataLenInvalid; 2415 2416 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2417 if (res) 2418 return res; 2419 2420 const auto* pBank = reinterpret_cast<const CrdMcaBank*>(data.data()); 2421 ss << std::format(" Bank ID : 0x{:02X}, Core ID : 0x{:02X}\n", 2422 hdr.bankHdr.bankId, hdr.bankHdr.coreId); 2423 ss << std::format(" MCA_CTRL : 0x{:016X}\n", pBank->mcaCtrl); 2424 ss << std::format(" MCA_STATUS : 0x{:016X}\n", pBank->mcaSts); 2425 ss << std::format(" MCA_ADDR : 0x{:016X}\n", pBank->mcaAddr); 2426 ss << std::format(" MCA_MISC0 : 0x{:016X}\n", pBank->mcaMisc0); 2427 ss << std::format(" MCA_CTRL_MASK : 0x{:016X}\n", pBank->mcaCtrlMask); 2428 ss << std::format(" MCA_CONFIG : 0x{:016X}\n", pBank->mcaConfig); 2429 ss << std::format(" MCA_IPID : 0x{:016X}\n", pBank->mcaIpid); 2430 ss << std::format(" MCA_SYND : 0x{:016X}\n", pBank->mcaSynd); 2431 ss << std::format(" MCA_DESTAT : 0x{:016X}\n", pBank->mcaDestat); 2432 ss << std::format(" MCA_DEADDR : 0x{:016X}\n", pBank->mcaDeaddr); 2433 ss << std::format(" MCA_MISC1 : 0x{:016X}\n", pBank->mcaMisc1); 2434 ss << "\n"; 2435 2436 return ipmi::ccSuccess; 2437 } 2438 2439 template <typename T> 2440 static ipmi_ret_t handleVirtualBank(std::span<const uint8_t> data, 2441 CrdState& currState, std::stringstream& ss) 2442 { 2443 if (data.size() < sizeof(T)) 2444 return ipmi::ccReqDataLenInvalid; 2445 2446 const auto* pBank = reinterpret_cast<const T*>(data.data()); 2447 2448 if (data.size() < sizeof(T) + sizeof(BankCorePair) * pBank->mcaCount) 2449 return ipmi::ccReqDataLenInvalid; 2450 2451 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2452 if (res) 2453 return res; 2454 2455 ss << " Virtual Bank\n"; 2456 ss << std::format(" S5_RESET_STATUS : 0x{:08X}\n", pBank->s5ResetSts); 2457 ss << std::format(" PM_BREAKEVENT : 0x{:08X}\n", pBank->breakevent); 2458 if constexpr (std::is_same_v<T, CrdVirtualBankV3>) 2459 { 2460 ss << std::format(" WARMCOLDRSTSTATUS : 0x{:08X}\n", pBank->rstSts); 2461 } 2462 ss << std::format(" PROCESSOR NUMBER : 0x{:04X}\n", pBank->procNum); 2463 ss << std::format(" APIC ID : 0x{:08X}\n", pBank->apicId); 2464 ss << std::format(" EAX : 0x{:08X}\n", pBank->eax); 2465 ss << std::format(" EBX : 0x{:08X}\n", pBank->ebx); 2466 ss << std::format(" ECX : 0x{:08X}\n", pBank->ecx); 2467 ss << std::format(" EDX : 0x{:08X}\n", pBank->edx); 2468 ss << " VALID LIST : "; 2469 for (size_t i = 0; i < pBank->mcaCount; i++) 2470 { 2471 ss << std::format("(0x{:02X},0x{:02X}) ", pBank->mcaList[i].bankId, 2472 pBank->mcaList[i].coreId); 2473 } 2474 ss << "\n\n"; 2475 2476 return ipmi::ccSuccess; 2477 } 2478 2479 static ipmi_ret_t handleCpuWdtBank(std::span<const uint8_t> data, 2480 CrdState& currState, std::stringstream& ss) 2481 { 2482 if (data.size() < sizeof(CrdCpuWdtBank)) 2483 return ipmi::ccReqDataLenInvalid; 2484 2485 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2486 if (res) 2487 return res; 2488 2489 const auto* pBank = reinterpret_cast<const CrdCpuWdtBank*>(data.data()); 2490 for (size_t i = 0; i < ccmNum; i++) 2491 { 2492 ss << std::format(" [CCM{}]\n", i); 2493 ss << std::format(" HwAssertStsHi : 0x{:08X}\n", 2494 pBank->hwAssertStsHi[i]); 2495 ss << std::format(" HwAssertStsLo : 0x{:08X}\n", 2496 pBank->hwAssertStsLo[i]); 2497 ss << std::format(" OrigWdtAddrLogHi : 0x{:08X}\n", 2498 pBank->origWdtAddrLogHi[i]); 2499 ss << std::format(" OrigWdtAddrLogLo : 0x{:08X}\n", 2500 pBank->origWdtAddrLogLo[i]); 2501 ss << std::format(" HwAssertMskHi : 0x{:08X}\n", 2502 pBank->hwAssertMskHi[i]); 2503 ss << std::format(" HwAssertMskLo : 0x{:08X}\n", 2504 pBank->hwAssertMskLo[i]); 2505 ss << std::format(" OrigWdtAddrLogStat : 0x{:08X}\n", 2506 pBank->origWdtAddrLogStat[i]); 2507 } 2508 ss << "\n"; 2509 2510 return ipmi::ccSuccess; 2511 } 2512 2513 template <size_t N> 2514 static ipmi_ret_t handleHwAssertBank(const char* name, 2515 std::span<const uint8_t> data, 2516 CrdState& currState, std::stringstream& ss) 2517 { 2518 if (data.size() < sizeof(CrdHwAssertBank<N>)) 2519 return ipmi::ccReqDataLenInvalid; 2520 2521 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2522 if (res) 2523 return res; 2524 2525 const CrdHwAssertBank<N>* pBank = 2526 reinterpret_cast<const CrdHwAssertBank<N>*>(data.data()); 2527 2528 for (size_t i = 0; i < N; i++) 2529 { 2530 ss << std::format(" [{}{}]\n", name, i); 2531 ss << std::format(" HwAssertStsHi : 0x{:08X}\n", 2532 pBank->hwAssertStsHi[i]); 2533 ss << std::format(" HwAssertStsLo : 0x{:08X}\n", 2534 pBank->hwAssertStsLo[i]); 2535 ss << std::format(" HwAssertMskHi : 0x{:08X}\n", 2536 pBank->hwAssertMskHi[i]); 2537 ss << std::format(" HwAssertMskLo : 0x{:08X}\n", 2538 pBank->hwAssertMskLo[i]); 2539 } 2540 ss << "\n"; 2541 2542 return ipmi::ccSuccess; 2543 } 2544 2545 static ipmi_ret_t handlePcieAerBank(std::span<const uint8_t> data, 2546 CrdState& currState, std::stringstream& ss) 2547 { 2548 if (data.size() < sizeof(CrdPcieAerBank)) 2549 return ipmi::ccReqDataLenInvalid; 2550 2551 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2552 if (res) 2553 return res; 2554 2555 const auto* pBank = reinterpret_cast<const CrdPcieAerBank*>(data.data()); 2556 ss << std::format(" [Bus{} Dev{} Fun{}]\n", pBank->bus, pBank->dev, 2557 pBank->fun); 2558 ss << std::format(" Command : 0x{:04X}\n", 2559 pBank->cmd); 2560 ss << std::format(" Status : 0x{:04X}\n", 2561 pBank->sts); 2562 ss << std::format(" Slot : 0x{:04X}\n", 2563 pBank->slot); 2564 ss << std::format(" Secondary Bus : 0x{:02X}\n", 2565 pBank->secondBus); 2566 ss << std::format(" Vendor ID : 0x{:04X}\n", 2567 pBank->vendorId); 2568 ss << std::format(" Device ID : 0x{:04X}\n", 2569 pBank->devId); 2570 ss << std::format(" Class Code : 0x{:02X}{:04X}\n", 2571 pBank->classCodeHi, pBank->classCodeLo); 2572 ss << std::format(" Bridge: Secondary Status : 0x{:04X}\n", 2573 pBank->secondSts); 2574 ss << std::format(" Bridge: Control : 0x{:04X}\n", 2575 pBank->ctrl); 2576 ss << std::format(" Uncorrectable Error Status : 0x{:08X}\n", 2577 pBank->uncorrErrSts); 2578 ss << std::format(" Uncorrectable Error Mask : 0x{:08X}\n", 2579 pBank->uncorrErrMsk); 2580 ss << std::format(" Uncorrectable Error Severity : 0x{:08X}\n", 2581 pBank->uncorrErrSeverity); 2582 ss << std::format(" Correctable Error Status : 0x{:08X}\n", 2583 pBank->corrErrSts); 2584 ss << std::format(" Correctable Error Mask : 0x{:08X}\n", 2585 pBank->corrErrMsk); 2586 ss << std::format(" Header Log DW0 : 0x{:08X}\n", 2587 pBank->hdrLogDw0); 2588 ss << std::format(" Header Log DW1 : 0x{:08X}\n", 2589 pBank->hdrLogDw1); 2590 ss << std::format(" Header Log DW2 : 0x{:08X}\n", 2591 pBank->hdrLogDw2); 2592 ss << std::format(" Header Log DW3 : 0x{:08X}\n", 2593 pBank->hdrLogDw3); 2594 ss << std::format(" Root Error Status : 0x{:08X}\n", 2595 pBank->rootErrSts); 2596 ss << std::format(" Correctable Error Source ID : 0x{:04X}\n", 2597 pBank->corrErrSrcId); 2598 ss << std::format(" Error Source ID : 0x{:04X}\n", 2599 pBank->errSrcId); 2600 ss << std::format(" Lane Error Status : 0x{:08X}\n", 2601 pBank->laneErrSts); 2602 ss << "\n"; 2603 2604 return ipmi::ccSuccess; 2605 } 2606 2607 static ipmi_ret_t handleWdtRegBank(std::span<const uint8_t> data, 2608 CrdState& currState, std::stringstream& ss) 2609 { 2610 if (data.size() < sizeof(CrdWdtRegBank)) 2611 return ipmi::ccReqDataLenInvalid; 2612 2613 const auto* pBank = reinterpret_cast<const CrdWdtRegBank*>(data.data()); 2614 if (data.size() < sizeof(CrdWdtRegBank) + sizeof(uint32_t) * pBank->count) 2615 return ipmi::ccReqDataLenInvalid; 2616 2617 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2618 if (res) 2619 return res; 2620 2621 ss << std::format(" [NBIO{}] {}\n", pBank->nbio, pBank->name); 2622 ss << std::format(" Address: 0x{:08X}\n", pBank->addr); 2623 ss << std::format(" Data Count: {}\n", pBank->count); 2624 ss << " Data:\n"; 2625 for (size_t i = 0; i < pBank->count; i++) 2626 { 2627 ss << std::format(" {}: 0x{:08X}\n", i, pBank->data[i]); 2628 } 2629 ss << "\n"; 2630 2631 return ipmi::ccSuccess; 2632 } 2633 2634 static ipmi_ret_t handleCrdHdrBank(std::span<const uint8_t> data, 2635 CrdState& currState, std::stringstream& ss) 2636 { 2637 if (data.size() < sizeof(CrdHdrBank)) 2638 return ipmi::ccReqDataLenInvalid; 2639 2640 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2641 if (res) 2642 return res; 2643 2644 const auto* pBank = reinterpret_cast<const CrdHdrBank*>(data.data()); 2645 ss << " Crashdump Header\n"; 2646 ss << std::format(" CPU PPIN : 0x{:016X}\n", pBank->ppin); 2647 ss << std::format(" UCODE VERSION : 0x{:08X}\n", pBank->ucodeVer); 2648 ss << std::format(" PMIO 80h : 0x{:08X}\n", pBank->pmio); 2649 ss << std::format( 2650 " BIT0 - SMN Parity/SMN Timeouts PSP/SMU Parity and ECC/SMN On-Package Link Error : {}\n", 2651 pBank->pmio & 0x1); 2652 ss << std::format(" BIT2 - PSP Parity and ECC : {}\n", 2653 (pBank->pmio & 0x4) >> 2); 2654 ss << std::format(" BIT3 - SMN Timeouts SMU : {}\n", 2655 (pBank->pmio & 0x8) >> 3); 2656 ss << std::format(" BIT4 - SMN Off-Package Link Packet Error : {}\n", 2657 (pBank->pmio & 0x10) >> 4); 2658 ss << "\n"; 2659 2660 return ipmi::ccSuccess; 2661 } 2662 2663 static std::string getFilename(const std::filesystem::path& dir, 2664 const std::string& prefix) 2665 { 2666 std::vector<int> indices; 2667 std::regex pattern(prefix + "(\\d+)\\.txt"); 2668 2669 for (const auto& entry : std::filesystem::directory_iterator(dir)) 2670 { 2671 std::string filename = entry.path().filename().string(); 2672 std::smatch match; 2673 if (std::regex_match(filename, match, pattern)) 2674 indices.push_back(std::stoi(match[1])); 2675 } 2676 2677 std::sort(indices.rbegin(), indices.rend()); 2678 while (indices.size() > 2) // keep 3 files, so remove if more than 2 2679 { 2680 std::filesystem::remove( 2681 dir / (prefix + std::to_string(indices.back()) + ".txt")); 2682 indices.pop_back(); 2683 } 2684 2685 int nextIndex = indices.empty() ? 1 : indices.front() + 1; 2686 return prefix + std::to_string(nextIndex) + ".txt"; 2687 } 2688 2689 static ipmi_ret_t handleCtrlBank(std::span<const uint8_t> data, 2690 CrdState& currState, std::stringstream& ss) 2691 { 2692 if (data.empty()) 2693 return ipmi::ccReqDataLenInvalid; 2694 2695 switch (static_cast<CrdCtrl>(data[0])) 2696 { 2697 case CrdCtrl::getState: 2698 break; 2699 case CrdCtrl::finish: 2700 { 2701 ipmi_ret_t res = setDumpState(currState, CrdState::packing); 2702 if (res) 2703 return res; 2704 2705 const std::filesystem::path dumpDir = "/var/lib/fb-ipmi-oem"; 2706 std::string filename = getFilename(dumpDir, "crashdump_"); 2707 std::ofstream outFile(dumpDir / filename); 2708 if (!outFile.is_open()) 2709 return ipmi::ccUnspecifiedError; 2710 2711 auto now = std::chrono::system_clock::to_time_t( 2712 std::chrono::system_clock::now()); 2713 outFile << "Crash Dump generated at: " 2714 << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S") 2715 << "\n\n"; 2716 outFile << ss.str(); 2717 outFile.close(); 2718 ss.str(""); 2719 ss.clear(); 2720 setDumpState(currState, CrdState::free); 2721 break; 2722 } 2723 default: 2724 return ccInvalidParam; 2725 } 2726 2727 return ipmi::ccSuccess; 2728 } 2729 2730 ipmi::RspType<std::vector<uint8_t>> ipmiOemCrashdump( 2731 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData) 2732 { 2733 static CrdState dumpState = CrdState::free; 2734 static std::stringstream ss; 2735 2736 if (reqData.size() < sizeof(CrashDumpHdr)) 2737 return ipmi::responseReqDataLenInvalid(); 2738 2739 const auto* pHdr = reinterpret_cast<const CrashDumpHdr*>(reqData.data()); 2740 std::span<const uint8_t> bData{reqData.data() + sizeof(CrashDumpHdr), 2741 reqData.size() - sizeof(CrashDumpHdr)}; 2742 ipmi_ret_t res; 2743 2744 switch (pHdr->bankHdr.bankType) 2745 { 2746 case BankType::mca: 2747 res = handleMcaBank(*pHdr, bData, dumpState, ss); 2748 break; 2749 case BankType::virt: 2750 if (pHdr->bankHdr.version >= 3) 2751 { 2752 res = handleVirtualBank<CrdVirtualBankV3>(bData, dumpState, ss); 2753 break; 2754 } 2755 res = handleVirtualBank<CrdVirtualBankV2>(bData, dumpState, ss); 2756 break; 2757 case BankType::cpuWdt: 2758 res = handleCpuWdtBank(bData, dumpState, ss); 2759 break; 2760 case BankType::tcdx: 2761 res = handleHwAssertBank<tcdxNum>("TCDX", bData, dumpState, ss); 2762 break; 2763 case BankType::cake: 2764 res = handleHwAssertBank<cakeNum>("CAKE", bData, dumpState, ss); 2765 break; 2766 case BankType::pie0: 2767 res = handleHwAssertBank<pie0Num>("PIE", bData, dumpState, ss); 2768 break; 2769 case BankType::iom: 2770 res = handleHwAssertBank<iomNum>("IOM", bData, dumpState, ss); 2771 break; 2772 case BankType::ccix: 2773 res = handleHwAssertBank<ccixNum>("CCIX", bData, dumpState, ss); 2774 break; 2775 case BankType::cs: 2776 res = handleHwAssertBank<csNum>("CS", bData, dumpState, ss); 2777 break; 2778 case BankType::pcieAer: 2779 res = handlePcieAerBank(bData, dumpState, ss); 2780 break; 2781 case BankType::wdtReg: 2782 res = handleWdtRegBank(bData, dumpState, ss); 2783 break; 2784 case BankType::ctrl: 2785 res = handleCtrlBank(bData, dumpState, ss); 2786 if (res == ipmi::ccSuccess && 2787 static_cast<CrdCtrl>(bData[0]) == CrdCtrl::getState) 2788 { 2789 return ipmi::responseSuccess( 2790 std::vector<uint8_t>{static_cast<uint8_t>(dumpState)}); 2791 } 2792 break; 2793 case BankType::crdHdr: 2794 res = handleCrdHdrBank(bData, dumpState, ss); 2795 break; 2796 default: 2797 return ipmi::responseInvalidFieldRequest(); 2798 } 2799 2800 return ipmi::response(res); 2801 } 2802 2803 static void registerOEMFunctions(void) 2804 { 2805 /* Get OEM data from json file */ 2806 std::ifstream file(JSON_OEM_DATA_FILE); 2807 if (file) 2808 { 2809 try 2810 { 2811 file >> oemData; 2812 } 2813 // If parsing fails, initialize oemData as an empty JSON and 2814 // overwrite the file 2815 catch (const nlohmann::json::parse_error& e) 2816 { 2817 lg2::error("Error parsing JSON file: {ERROR}", "ERROR", e); 2818 oemData = nlohmann::json::object(); 2819 std::ofstream outFile(JSON_OEM_DATA_FILE, std::ofstream::trunc); 2820 outFile << oemData.dump(4); // Write empty JSON object to the file 2821 outFile.close(); 2822 } 2823 file.close(); 2824 } 2825 else 2826 { 2827 lg2::info("Failed to open JSON file."); 2828 } 2829 2830 lg2::info("Registering OEM commands."); 2831 2832 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO, 2833 NULL, ipmiOemDbgGetFrameInfo, 2834 PRIVILEGE_USER); // get debug frame info 2835 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, 2836 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL, 2837 ipmiOemDbgGetUpdFrames, 2838 PRIVILEGE_USER); // get debug updated frames 2839 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC, 2840 NULL, ipmiOemDbgGetPostDesc, 2841 PRIVILEGE_USER); // get debug post description 2842 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC, 2843 NULL, ipmiOemDbgGetGpioDesc, 2844 PRIVILEGE_USER); // get debug gpio description 2845 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA, 2846 NULL, ipmiOemDbgGetFrameData, 2847 PRIVILEGE_USER); // get debug frame data 2848 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL, 2849 NULL, ipmiOemDbgGetCtrlPanel, 2850 PRIVILEGE_USER); // get debug control panel 2851 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_DIMM_INFO, NULL, 2852 ipmiOemSetDimmInfo, 2853 PRIVILEGE_USER); // Set Dimm Info 2854 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_BOARD_ID, NULL, 2855 ipmiOemGetBoardID, 2856 PRIVILEGE_USER); // Get Board ID 2857 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne, 2858 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User, 2859 ipmiOemGet80PortRecord); // Get 80 Port Record 2860 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_MACHINE_CONFIG_INFO, 2861 NULL, ipmiOemSetMachineCfgInfo, 2862 PRIVILEGE_USER); // Set Machine Config Info 2863 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_START, NULL, 2864 ipmiOemSetPostStart, 2865 PRIVILEGE_USER); // Set POST start 2866 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_END, NULL, 2867 ipmiOemSetPostEnd, 2868 PRIVILEGE_USER); // Set POST End 2869 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPIN_INFO, NULL, 2870 ipmiOemSetPPINInfo, 2871 PRIVILEGE_USER); // Set PPIN Info 2872 #if BIC_ENABLED 2873 2874 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2875 ipmi::cmdSetSystemGuid, ipmi::Privilege::User, 2876 ipmiOemSetSystemGuid); 2877 #else 2878 2879 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_SYSTEM_GUID, NULL, 2880 ipmiOemSetSystemGuid, 2881 PRIVILEGE_USER); // Set System GUID 2882 #endif 2883 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_ADR_TRIGGER, NULL, 2884 ipmiOemSetAdrTrigger, 2885 PRIVILEGE_USER); // Set ADR Trigger 2886 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_BIOS_FLASH_INFO, NULL, 2887 ipmiOemSetBiosFlashInfo, 2888 PRIVILEGE_USER); // Set Bios Flash Info 2889 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPR, NULL, 2890 ipmiOemSetPpr, 2891 PRIVILEGE_USER); // Set PPR 2892 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_PPR, NULL, 2893 ipmiOemGetPpr, 2894 PRIVILEGE_USER); // Get PPR 2895 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_FRU_ID, NULL, 2896 ipmiOemGetFruId, 2897 PRIVILEGE_USER); // Get FRU ID 2898 /* FB OEM QC Commands */ 2899 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2900 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User, 2901 ipmiOemQSetProcInfo); // Set Proc Info 2902 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2903 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User, 2904 ipmiOemQGetProcInfo); // Get Proc Info 2905 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2906 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User, 2907 ipmiOemQSetDimmInfo); // Set Dimm Info 2908 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2909 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User, 2910 ipmiOemQGetDimmInfo); // Get Dimm Info 2911 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL, 2912 ipmiOemQSetDriveInfo, 2913 PRIVILEGE_USER); // Set Drive Info 2914 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL, 2915 ipmiOemQGetDriveInfo, 2916 PRIVILEGE_USER); // Get Drive Info 2917 2918 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */ 2919 ipmi::registerGroupHandler( 2920 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerReading, 2921 ipmi::Privilege::User, 2922 ipmiOemDCMIGetPowerReading); // Get Power Reading 2923 2924 ipmi::registerGroupHandler( 2925 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerLimit, 2926 ipmi::Privilege::User, 2927 ipmiOemDCMIGetPowerLimit); // Get Power Limit 2928 2929 ipmi::registerGroupHandler( 2930 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdSetPowerLimit, 2931 ipmi::Privilege::Operator, 2932 ipmiOemDCMISetPowerLimit); // Set Power Limit 2933 2934 ipmi::registerGroupHandler( 2935 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdActDeactivatePwrLimit, 2936 ipmi::Privilege::Operator, 2937 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit 2938 2939 /* FB OEM BOOT ORDER COMMANDS */ 2940 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2941 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User, 2942 ipmiOemGetBootOrder); // Get Boot Order 2943 2944 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2945 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User, 2946 ipmiOemSetBootOrder); // Set Boot Order 2947 2948 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2949 CMD_OEM_GET_HTTPS_BOOT_DATA, ipmi::Privilege::User, 2950 ipmiOemGetHttpsData); 2951 2952 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2953 CMD_OEM_GET_HTTPS_BOOT_ATTR, ipmi::Privilege::User, 2954 ipmiOemGetHttpsAttr); 2955 2956 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2957 CMD_OEM_CRASHDUMP, ipmi::Privilege::User, 2958 ipmiOemCrashdump); 2959 2960 return; 2961 } 2962 2963 } // namespace ipmi 2964