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