1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 17 #include "xyz/openbmc_project/Common/error.hpp" 18 #include "xyz/openbmc_project/Led/Physical/server.hpp" 19 20 #include <systemd/sd-journal.h> 21 22 #include <array> 23 #include <boost/container/flat_map.hpp> 24 #include <boost/process/child.hpp> 25 #include <boost/process/io.hpp> 26 #include <com/intel/Control/NMISource/server.hpp> 27 #include <com/intel/Control/OCOTShutdownPolicy/server.hpp> 28 #include <commandutils.hpp> 29 #include <filesystem> 30 #include <iostream> 31 #include <ipmid/api.hpp> 32 #include <ipmid/utils.hpp> 33 #include <nlohmann/json.hpp> 34 #include <oemcommands.hpp> 35 #include <phosphor-logging/log.hpp> 36 #include <sdbusplus/bus.hpp> 37 #include <sdbusplus/message/types.hpp> 38 #include <string> 39 #include <variant> 40 #include <vector> 41 #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> 42 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> 43 #include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp> 44 #include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp> 45 46 namespace ipmi 47 { 48 static void registerOEMFunctions() __attribute__((constructor)); 49 50 namespace netfn::intel 51 { 52 constexpr NetFn oemGeneral = netFnOemOne; 53 constexpr Cmd cmdRestoreConfiguration = 0x02; 54 } // namespace netfn::intel 55 56 static constexpr size_t maxFRUStringLength = 0x3F; 57 58 static constexpr auto ethernetIntf = 59 "xyz.openbmc_project.Network.EthernetInterface"; 60 static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP"; 61 static constexpr auto networkService = "xyz.openbmc_project.Network"; 62 static constexpr auto networkRoot = "/xyz/openbmc_project/network"; 63 64 static constexpr const char* oemNmiSourceIntf = "com.intel.Control.NMISource"; 65 static constexpr const char* oemNmiSourceObjPath = 66 "/com/intel/control/NMISource"; 67 static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource"; 68 static constexpr const char* oemNmiEnabledObjPathProp = "Enabled"; 69 70 static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json"; 71 72 enum class NmiSource : uint8_t 73 { 74 none = 0, 75 fpBtn = 1, 76 wdPreTimeout = 2, 77 pefMatch = 3, 78 chassisCmd = 4, 79 memoryError = 5, 80 pciSerrPerr = 6, 81 southbridgeNmi = 7, 82 chipsetNmi = 8, 83 }; 84 85 static constexpr const char* restricionModeService = 86 "xyz.openbmc_project.RestrictionMode.Manager"; 87 static constexpr const char* restricionModeBasePath = 88 "/xyz/openbmc_project/control/security/restriction_mode"; 89 static constexpr const char* restricionModeIntf = 90 "xyz.openbmc_project.Control.Security.RestrictionMode"; 91 static constexpr const char* restricionModeProperty = "RestrictionMode"; 92 93 static constexpr const char* specialModeService = 94 "xyz.openbmc_project.SpecialMode"; 95 static constexpr const char* specialModeBasePath = 96 "/xyz/openbmc_project/security/specialMode"; 97 static constexpr const char* specialModeIntf = 98 "xyz.openbmc_project.Security.SpecialMode"; 99 static constexpr const char* specialModeProperty = "SpecialMode"; 100 101 static constexpr const char* dBusPropertyIntf = 102 "org.freedesktop.DBus.Properties"; 103 static constexpr const char* dBusPropertyGetMethod = "Get"; 104 static constexpr const char* dBusPropertySetMethod = "Set"; 105 106 // return code: 0 successful 107 int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial) 108 { 109 std::string objpath = "/xyz/openbmc_project/FruDevice"; 110 std::string intf = "xyz.openbmc_project.FruDeviceManager"; 111 std::string service = getService(bus, intf, objpath); 112 ObjectValueTree valueTree = getManagedObjects(bus, service, "/"); 113 if (valueTree.empty()) 114 { 115 phosphor::logging::log<phosphor::logging::level::ERR>( 116 "No object implements interface", 117 phosphor::logging::entry("INTF=%s", intf.c_str())); 118 return -1; 119 } 120 121 for (const auto& item : valueTree) 122 { 123 auto interface = item.second.find("xyz.openbmc_project.FruDevice"); 124 if (interface == item.second.end()) 125 { 126 continue; 127 } 128 129 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER"); 130 if (property == interface->second.end()) 131 { 132 continue; 133 } 134 135 try 136 { 137 Value variant = property->second; 138 std::string& result = std::get<std::string>(variant); 139 if (result.size() > maxFRUStringLength) 140 { 141 phosphor::logging::log<phosphor::logging::level::ERR>( 142 "FRU serial number exceed maximum length"); 143 return -1; 144 } 145 serial = result; 146 return 0; 147 } 148 catch (std::bad_variant_access& e) 149 { 150 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 151 return -1; 152 } 153 } 154 return -1; 155 } 156 157 ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 158 ipmi_request_t request, ipmi_response_t response, 159 ipmi_data_len_t dataLen, ipmi_context_t context) 160 { 161 printCommand(+netfn, +cmd); 162 // Status code. 163 ipmi_ret_t rc = IPMI_CC_INVALID; 164 *dataLen = 0; 165 return rc; 166 } 167 168 // Returns the Chassis Identifier (serial #) 169 ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 170 ipmi_request_t request, 171 ipmi_response_t response, 172 ipmi_data_len_t dataLen, 173 ipmi_context_t context) 174 { 175 std::string serial; 176 if (*dataLen != 0) // invalid request if there are extra parameters 177 { 178 *dataLen = 0; 179 return IPMI_CC_REQ_DATA_LEN_INVALID; 180 } 181 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 182 if (getChassisSerialNumber(*dbus, serial) == 0) 183 { 184 *dataLen = serial.size(); // length will never exceed response length 185 // as it is checked in getChassisSerialNumber 186 char* resp = static_cast<char*>(response); 187 serial.copy(resp, *dataLen); 188 return IPMI_CC_OK; 189 } 190 *dataLen = 0; 191 return IPMI_CC_RESPONSE_ERROR; 192 } 193 194 ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 195 ipmi_request_t request, 196 ipmi_response_t response, 197 ipmi_data_len_t dataLen, ipmi_context_t context) 198 { 199 static constexpr size_t safeBufferLength = 50; 200 char buf[safeBufferLength] = {0}; 201 GUIDData* Data = reinterpret_cast<GUIDData*>(request); 202 203 if (*dataLen != sizeof(GUIDData)) // 16bytes 204 { 205 *dataLen = 0; 206 return IPMI_CC_REQ_DATA_LEN_INVALID; 207 } 208 209 *dataLen = 0; 210 211 snprintf( 212 buf, safeBufferLength, 213 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 214 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1, 215 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1, 216 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4, 217 Data->node3, Data->node2, Data->node1); 218 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 219 std::string guid = buf; 220 221 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID"; 222 std::string intf = "xyz.openbmc_project.Common.UUID"; 223 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 224 std::string service = getService(*dbus, intf, objpath); 225 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid); 226 return IPMI_CC_OK; 227 } 228 229 ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI, 230 uint7_t reserved1) 231 { 232 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 233 234 try 235 { 236 auto service = 237 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath); 238 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath, 239 bmcResetDisablesIntf, "ResetOnSMI", 240 !disableResetOnSMI); 241 } 242 catch (std::exception& e) 243 { 244 phosphor::logging::log<phosphor::logging::level::ERR>( 245 "Failed to set BMC reset disables", 246 phosphor::logging::entry("EXCEPTION=%s", e.what())); 247 return ipmi::responseUnspecifiedError(); 248 } 249 250 return ipmi::responseSuccess(); 251 } 252 253 ipmi::RspType<bool, // disableResetOnSMI 254 uint7_t // reserved 255 > 256 ipmiOEMGetBMCResetDisables() 257 { 258 bool disableResetOnSMI = true; 259 260 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 261 try 262 { 263 auto service = 264 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath); 265 Value variant = 266 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath, 267 bmcResetDisablesIntf, "ResetOnSMI"); 268 disableResetOnSMI = !std::get<bool>(variant); 269 } 270 catch (std::exception& e) 271 { 272 phosphor::logging::log<phosphor::logging::level::ERR>( 273 "Failed to get BMC reset disables", 274 phosphor::logging::entry("EXCEPTION=%s", e.what())); 275 return ipmi::responseUnspecifiedError(); 276 } 277 278 return ipmi::responseSuccess(disableResetOnSMI, 0); 279 } 280 281 ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 282 ipmi_request_t request, ipmi_response_t response, 283 ipmi_data_len_t dataLen, ipmi_context_t context) 284 { 285 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request); 286 287 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength))) 288 { 289 *dataLen = 0; 290 return IPMI_CC_REQ_DATA_LEN_INVALID; 291 } 292 std::string idString((char*)data->biosId, data->biosIDLength); 293 294 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 295 std::string service = getService(*dbus, biosIntf, biosObjPath); 296 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString); 297 uint8_t* bytesWritten = static_cast<uint8_t*>(response); 298 *bytesWritten = 299 data->biosIDLength; // how many bytes are written into storage 300 *dataLen = 1; 301 return IPMI_CC_OK; 302 } 303 304 ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 305 ipmi_request_t request, 306 ipmi_response_t response, 307 ipmi_data_len_t dataLen, ipmi_context_t context) 308 { 309 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request); 310 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response); 311 312 if (*dataLen == 0) 313 { 314 *dataLen = 0; 315 return IPMI_CC_REQ_DATA_LEN_INVALID; 316 } 317 318 size_t reqDataLen = *dataLen; 319 *dataLen = 0; 320 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer)) 321 { 322 return IPMI_CC_INVALID_FIELD_REQUEST; 323 } 324 325 // handle OEM command items 326 switch (OEMDevEntityType(req->entityType)) 327 { 328 case OEMDevEntityType::biosId: 329 { 330 if (sizeof(GetOemDeviceInfoReq) != reqDataLen) 331 { 332 return IPMI_CC_REQ_DATA_LEN_INVALID; 333 } 334 335 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 336 std::string service = getService(*dbus, biosIntf, biosObjPath); 337 try 338 { 339 Value variant = getDbusProperty(*dbus, service, biosObjPath, 340 biosIntf, biosProp); 341 std::string& idString = std::get<std::string>(variant); 342 if (req->offset >= idString.size()) 343 { 344 return IPMI_CC_PARM_OUT_OF_RANGE; 345 } 346 size_t length = 0; 347 if (req->countToRead > (idString.size() - req->offset)) 348 { 349 length = idString.size() - req->offset; 350 } 351 else 352 { 353 length = req->countToRead; 354 } 355 std::copy(idString.begin() + req->offset, idString.end(), 356 res->data); 357 res->resDatalen = length; 358 *dataLen = res->resDatalen + 1; 359 } 360 catch (std::bad_variant_access& e) 361 { 362 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 363 return IPMI_CC_UNSPECIFIED_ERROR; 364 } 365 } 366 break; 367 368 case OEMDevEntityType::devVer: 369 case OEMDevEntityType::sdrVer: 370 // TODO: 371 return IPMI_CC_ILLEGAL_COMMAND; 372 default: 373 return IPMI_CC_INVALID_FIELD_REQUEST; 374 } 375 return IPMI_CC_OK; 376 } 377 378 ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 379 ipmi_request_t request, ipmi_response_t response, 380 ipmi_data_len_t dataLen, ipmi_context_t context) 381 { 382 if (*dataLen != 0) 383 { 384 *dataLen = 0; 385 return IPMI_CC_REQ_DATA_LEN_INVALID; 386 } 387 388 *dataLen = 1; 389 uint8_t* res = reinterpret_cast<uint8_t*>(response); 390 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no 391 // AIC is available so that BIOS will not timeout repeatly which leads to 392 // slow booting. 393 *res = 0; // Byte1=Count of SlotPosition/FruID records. 394 return IPMI_CC_OK; 395 } 396 397 ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 398 ipmi_request_t request, 399 ipmi_response_t response, 400 ipmi_data_len_t dataLen, 401 ipmi_context_t context) 402 { 403 GetPowerRestoreDelayRes* resp = 404 reinterpret_cast<GetPowerRestoreDelayRes*>(response); 405 406 if (*dataLen != 0) 407 { 408 *dataLen = 0; 409 return IPMI_CC_REQ_DATA_LEN_INVALID; 410 } 411 412 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 413 std::string service = 414 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath); 415 Value variant = 416 getDbusProperty(*dbus, service, powerRestoreDelayObjPath, 417 powerRestoreDelayIntf, powerRestoreDelayProp); 418 419 uint16_t delay = std::get<uint16_t>(variant); 420 resp->byteLSB = delay; 421 resp->byteMSB = delay >> 8; 422 423 *dataLen = sizeof(GetPowerRestoreDelayRes); 424 425 return IPMI_CC_OK; 426 } 427 428 static uint8_t bcdToDec(uint8_t val) 429 { 430 return ((val / 16 * 10) + (val % 16)); 431 } 432 433 // Allows an update utility or system BIOS to send the status of an embedded 434 // firmware update attempt to the BMC. After received, BMC will create a logging 435 // record. 436 ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target, 437 uint8_t majorRevision, 438 uint8_t minorRevision, 439 uint32_t auxInfo) 440 { 441 std::string firmware; 442 int instance = (target & targetInstanceMask) >> targetInstanceShift; 443 target = (target & selEvtTargetMask) >> selEvtTargetShift; 444 445 /* make sure the status is 0, 1, or 2 as per the spec */ 446 if (status > 2) 447 { 448 return ipmi::response(ipmi::ccInvalidFieldRequest); 449 } 450 /* make sure the target is 0, 1, 2, or 4 as per the spec */ 451 if (target > 4 || target == 3) 452 { 453 return ipmi::response(ipmi::ccInvalidFieldRequest); 454 } 455 /*orignal OEM command is to record OEM SEL. 456 But openbmc does not support OEM SEL, so we redirect it to redfish event 457 logging. */ 458 std::string buildInfo; 459 std::string action; 460 switch (FWUpdateTarget(target)) 461 { 462 case FWUpdateTarget::targetBMC: 463 firmware = "BMC"; 464 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " + 465 std::to_string(bcdToDec(minorRevision)) + // BCD encoded 466 " BuildID: " + std::to_string(auxInfo); 467 buildInfo += std::to_string(auxInfo); 468 break; 469 case FWUpdateTarget::targetBIOS: 470 firmware = "BIOS"; 471 buildInfo = 472 "major: " + 473 std::to_string(bcdToDec(majorRevision)) + // BCD encoded 474 " minor: " + 475 std::to_string(bcdToDec(minorRevision)) + // BCD encoded 476 " ReleaseNumber: " + // ASCII encoded 477 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') + 478 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') + 479 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') + 480 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0'); 481 break; 482 case FWUpdateTarget::targetME: 483 firmware = "ME"; 484 buildInfo = 485 "major: " + std::to_string(majorRevision) + " minor1: " + 486 std::to_string(bcdToDec(minorRevision)) + // BCD encoded 487 " minor2: " + 488 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) + 489 " build1: " + 490 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) + 491 " build2: " + 492 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16))); 493 break; 494 case FWUpdateTarget::targetOEMEWS: 495 firmware = "EWS"; 496 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " + 497 std::to_string(bcdToDec(minorRevision)) + // BCD encoded 498 " BuildID: " + std::to_string(auxInfo); 499 break; 500 } 501 502 static const std::string openBMCMessageRegistryVersion("0.1"); 503 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion; 504 505 switch (status) 506 { 507 case 0x0: 508 action = "update started"; 509 redfishMsgID += ".FirmwareUpdateStarted"; 510 break; 511 case 0x1: 512 action = "update completed successfully"; 513 redfishMsgID += ".FirmwareUpdateCompleted"; 514 break; 515 case 0x2: 516 action = "update failure"; 517 redfishMsgID += ".FirmwareUpdateFailed"; 518 break; 519 default: 520 action = "unknown"; 521 break; 522 } 523 524 std::string firmwareInstanceStr = 525 firmware + " instance: " + std::to_string(instance); 526 std::string message("[firmware update] " + firmwareInstanceStr + 527 " status: <" + action + "> " + buildInfo); 528 529 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO, 530 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(), 531 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(), 532 buildInfo.c_str(), NULL); 533 return ipmi::responseSuccess(); 534 } 535 536 ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 537 ipmi_request_t request, 538 ipmi_response_t response, 539 ipmi_data_len_t dataLen, 540 ipmi_context_t context) 541 { 542 SetPowerRestoreDelayReq* data = 543 reinterpret_cast<SetPowerRestoreDelayReq*>(request); 544 uint16_t delay = 0; 545 546 if (*dataLen != sizeof(SetPowerRestoreDelayReq)) 547 { 548 *dataLen = 0; 549 return IPMI_CC_REQ_DATA_LEN_INVALID; 550 } 551 delay = data->byteMSB; 552 delay = (delay << 8) | data->byteLSB; 553 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 554 std::string service = 555 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath); 556 setDbusProperty(*dbus, service, powerRestoreDelayObjPath, 557 powerRestoreDelayIntf, powerRestoreDelayProp, delay); 558 *dataLen = 0; 559 560 return IPMI_CC_OK; 561 } 562 563 static bool cpuPresent(const std::string& cpuName) 564 { 565 static constexpr const char* cpuPresencePathPrefix = 566 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"; 567 static constexpr const char* cpuPresenceIntf = 568 "xyz.openbmc_project.Inventory.Item"; 569 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName; 570 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 571 try 572 { 573 auto service = 574 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath); 575 576 ipmi::Value result = ipmi::getDbusProperty( 577 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present"); 578 return std::get<bool>(result); 579 } 580 catch (const std::exception& e) 581 { 582 phosphor::logging::log<phosphor::logging::level::INFO>( 583 "Cannot find processor presence", 584 phosphor::logging::entry("NAME=%s", cpuName.c_str())); 585 return false; 586 } 587 } 588 589 ipmi::RspType<bool, // CATERR Reset Enabled 590 bool, // ERR2 Reset Enabled 591 uint6_t, // reserved 592 uint8_t, // reserved, returns 0x3F 593 uint6_t, // CPU1 CATERR Count 594 uint2_t, // CPU1 Status 595 uint6_t, // CPU2 CATERR Count 596 uint2_t, // CPU2 Status 597 uint6_t, // CPU3 CATERR Count 598 uint2_t, // CPU3 Status 599 uint6_t, // CPU4 CATERR Count 600 uint2_t, // CPU4 Status 601 uint8_t // Crashdump Count 602 > 603 ipmiOEMGetProcessorErrConfig() 604 { 605 bool resetOnCATERR = false; 606 bool resetOnERR2 = false; 607 uint6_t cpu1CATERRCount = 0; 608 uint6_t cpu2CATERRCount = 0; 609 uint6_t cpu3CATERRCount = 0; 610 uint6_t cpu4CATERRCount = 0; 611 uint8_t crashdumpCount = 0; 612 uint2_t cpu1Status = 613 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent; 614 uint2_t cpu2Status = 615 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent; 616 uint2_t cpu3Status = 617 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent; 618 uint2_t cpu4Status = 619 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent; 620 621 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 622 try 623 { 624 auto service = ipmi::getService(*busp, processorErrConfigIntf, 625 processorErrConfigObjPath); 626 627 ipmi::PropertyMap result = ipmi::getAllDbusProperties( 628 *busp, service, processorErrConfigObjPath, processorErrConfigIntf); 629 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR")); 630 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2")); 631 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1")); 632 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2")); 633 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3")); 634 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4")); 635 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount")); 636 } 637 catch (const std::exception& e) 638 { 639 phosphor::logging::log<phosphor::logging::level::ERR>( 640 "Failed to fetch processor error config", 641 phosphor::logging::entry("ERROR=%s", e.what())); 642 return ipmi::responseUnspecifiedError(); 643 } 644 645 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F, 646 cpu1CATERRCount, cpu1Status, cpu2CATERRCount, 647 cpu2Status, cpu3CATERRCount, cpu3Status, 648 cpu4CATERRCount, cpu4Status, crashdumpCount); 649 } 650 651 ipmi::RspType<> ipmiOEMSetProcessorErrConfig( 652 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2, 653 std::optional<bool> clearCPUErrorCount, 654 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3) 655 { 656 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 657 658 try 659 { 660 auto service = ipmi::getService(*busp, processorErrConfigIntf, 661 processorErrConfigObjPath); 662 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 663 processorErrConfigIntf, "ResetOnCATERR", 664 resetOnCATERR); 665 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 666 processorErrConfigIntf, "ResetOnERR2", 667 resetOnERR2); 668 if (clearCPUErrorCount.value_or(false)) 669 { 670 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 671 processorErrConfigIntf, "ErrorCountCPU1", 672 static_cast<uint8_t>(0)); 673 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 674 processorErrConfigIntf, "ErrorCountCPU2", 675 static_cast<uint8_t>(0)); 676 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 677 processorErrConfigIntf, "ErrorCountCPU3", 678 static_cast<uint8_t>(0)); 679 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 680 processorErrConfigIntf, "ErrorCountCPU4", 681 static_cast<uint8_t>(0)); 682 } 683 if (clearCrashdumpCount.value_or(false)) 684 { 685 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 686 processorErrConfigIntf, "CrashdumpCount", 687 static_cast<uint8_t>(0)); 688 } 689 } 690 catch (std::exception& e) 691 { 692 phosphor::logging::log<phosphor::logging::level::ERR>( 693 "Failed to set processor error config", 694 phosphor::logging::entry("EXCEPTION=%s", e.what())); 695 return ipmi::responseUnspecifiedError(); 696 } 697 698 return ipmi::responseSuccess(); 699 } 700 701 ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 702 ipmi_request_t request, 703 ipmi_response_t response, 704 ipmi_data_len_t dataLen, 705 ipmi_context_t context) 706 { 707 GetOEMShutdownPolicyRes* resp = 708 reinterpret_cast<GetOEMShutdownPolicyRes*>(response); 709 710 if (*dataLen != 0) 711 { 712 phosphor::logging::log<phosphor::logging::level::ERR>( 713 "oem_get_shutdown_policy: invalid input len!"); 714 *dataLen = 0; 715 return IPMI_CC_REQ_DATA_LEN_INVALID; 716 } 717 718 *dataLen = 0; 719 720 try 721 { 722 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 723 std::string service = 724 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath); 725 Value variant = getDbusProperty( 726 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf, 727 oemShutdownPolicyObjPathProp); 728 729 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 730 convertPolicyFromString(std::get<std::string>(variant)) == 731 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy:: 732 NoShutdownOnOCOT) 733 { 734 resp->policy = 0; 735 } 736 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 737 convertPolicyFromString(std::get<std::string>(variant)) == 738 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 739 Policy::ShutdownOnOCOT) 740 { 741 resp->policy = 1; 742 } 743 else 744 { 745 phosphor::logging::log<phosphor::logging::level::ERR>( 746 "oem_set_shutdown_policy: invalid property!", 747 phosphor::logging::entry( 748 "PROP=%s", std::get<std::string>(variant).c_str())); 749 return IPMI_CC_UNSPECIFIED_ERROR; 750 } 751 // TODO needs to check if it is multi-node products, 752 // policy is only supported on node 3/4 753 resp->policySupport = shutdownPolicySupported; 754 } 755 catch (sdbusplus::exception_t& e) 756 { 757 phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 758 return IPMI_CC_UNSPECIFIED_ERROR; 759 } 760 761 *dataLen = sizeof(GetOEMShutdownPolicyRes); 762 return IPMI_CC_OK; 763 } 764 765 ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 766 ipmi_request_t request, 767 ipmi_response_t response, 768 ipmi_data_len_t dataLen, 769 ipmi_context_t context) 770 { 771 uint8_t* req = reinterpret_cast<uint8_t*>(request); 772 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy = 773 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy:: 774 NoShutdownOnOCOT; 775 776 // TODO needs to check if it is multi-node products, 777 // policy is only supported on node 3/4 778 if (*dataLen != 1) 779 { 780 phosphor::logging::log<phosphor::logging::level::ERR>( 781 "oem_set_shutdown_policy: invalid input len!"); 782 *dataLen = 0; 783 return IPMI_CC_REQ_DATA_LEN_INVALID; 784 } 785 786 *dataLen = 0; 787 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT)) 788 { 789 phosphor::logging::log<phosphor::logging::level::ERR>( 790 "oem_set_shutdown_policy: invalid input!"); 791 return IPMI_CC_INVALID_FIELD_REQUEST; 792 } 793 794 if (*req == noShutdownOnOCOT) 795 { 796 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 797 Policy::NoShutdownOnOCOT; 798 } 799 else 800 { 801 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 802 Policy::ShutdownOnOCOT; 803 } 804 805 try 806 { 807 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 808 std::string service = 809 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath); 810 setDbusProperty( 811 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf, 812 oemShutdownPolicyObjPathProp, 813 sdbusplus::com::intel::Control::server::convertForMessage(policy)); 814 } 815 catch (sdbusplus::exception_t& e) 816 { 817 phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 818 return IPMI_CC_UNSPECIFIED_ERROR; 819 } 820 821 return IPMI_CC_OK; 822 } 823 824 /** @brief implementation for check the DHCP or not in IPv4 825 * @param[in] Channel - Channel number 826 * @returns true or false. 827 */ 828 static bool isDHCPEnabled(uint8_t Channel) 829 { 830 try 831 { 832 auto ethdevice = getChannelName(Channel); 833 if (ethdevice.empty()) 834 { 835 return false; 836 } 837 auto ethIP = ethdevice + "/ipv4"; 838 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 839 auto ethernetObj = 840 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP); 841 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first, 842 networkIPIntf, "Origin"); 843 if (std::get<std::string>(value) == 844 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 845 { 846 return true; 847 } 848 else 849 { 850 return false; 851 } 852 } 853 catch (sdbusplus::exception_t& e) 854 { 855 phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 856 return true; 857 } 858 } 859 860 /** @brief implementes for check the DHCP or not in IPv6 861 * @param[in] Channel - Channel number 862 * @returns true or false. 863 */ 864 static bool isDHCPIPv6Enabled(uint8_t Channel) 865 { 866 867 try 868 { 869 auto ethdevice = getChannelName(Channel); 870 if (ethdevice.empty()) 871 { 872 return false; 873 } 874 auto ethIP = ethdevice + "/ipv6"; 875 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 876 auto objectInfo = 877 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP); 878 auto properties = getAllDbusProperties(*dbus, objectInfo.second, 879 objectInfo.first, networkIPIntf); 880 if (std::get<std::string>(properties["Origin"]) == 881 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 882 { 883 return true; 884 } 885 else 886 { 887 return false; 888 } 889 } 890 catch (sdbusplus::exception_t& e) 891 { 892 phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 893 return true; 894 } 895 } 896 897 /** @brief implementes the creating of default new user 898 * @param[in] userName - new username in 16 bytes. 899 * @param[in] userPassword - new password in 20 bytes 900 * @returns ipmi completion code. 901 */ 902 ipmi::RspType<> ipmiOEMSetUser2Activation( 903 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName, 904 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword) 905 { 906 bool userState = false; 907 // Check for System Interface not exist and LAN should be static 908 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++) 909 { 910 ChannelInfo chInfo; 911 try 912 { 913 getChannelInfo(channel, chInfo); 914 } 915 catch (sdbusplus::exception_t& e) 916 { 917 phosphor::logging::log<phosphor::logging::level::ERR>( 918 "ipmiOEMSetUser2Activation: Failed to get Channel Info", 919 phosphor::logging::entry("MSG: %s", e.description())); 920 return ipmi::response(ipmi::ccUnspecifiedError); 921 } 922 if (chInfo.mediumType == 923 static_cast<uint8_t>(EChannelMediumType::systemInterface)) 924 { 925 phosphor::logging::log<phosphor::logging::level::ERR>( 926 "ipmiOEMSetUser2Activation: system interface exist ."); 927 return ipmi::response(ipmi::ccCommandNotAvailable); 928 } 929 else 930 { 931 932 if (chInfo.mediumType == 933 static_cast<uint8_t>(EChannelMediumType::lan8032)) 934 { 935 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel)) 936 { 937 phosphor::logging::log<phosphor::logging::level::ERR>( 938 "ipmiOEMSetUser2Activation: DHCP enabled ."); 939 return ipmi::response(ipmi::ccCommandNotAvailable); 940 } 941 } 942 } 943 } 944 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0; 945 if (ipmi::ccSuccess == 946 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers)) 947 { 948 if (enabledUsers > 1) 949 { 950 phosphor::logging::log<phosphor::logging::level::ERR>( 951 "ipmiOEMSetUser2Activation: more than one user is enabled."); 952 return ipmi::response(ipmi::ccCommandNotAvailable); 953 } 954 // Check the user 2 is enabled or not 955 ipmiUserCheckEnabled(ipmiDefaultUserId, userState); 956 if (userState == true) 957 { 958 phosphor::logging::log<phosphor::logging::level::ERR>( 959 "ipmiOEMSetUser2Activation: user 2 already enabled ."); 960 return ipmi::response(ipmi::ccCommandNotAvailable); 961 } 962 } 963 else 964 { 965 return ipmi::response(ipmi::ccUnspecifiedError); 966 } 967 968 #if BYTE_ORDER == LITTLE_ENDIAN 969 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0}; 970 #endif 971 #if BYTE_ORDER == BIG_ENDIAN 972 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN}; 973 #endif 974 975 if (ipmi::ccSuccess == 976 ipmiUserSetUserName(ipmiDefaultUserId, 977 reinterpret_cast<const char*>(userName.data()))) 978 { 979 if (ipmi::ccSuccess == 980 ipmiUserSetUserPassword( 981 ipmiDefaultUserId, 982 reinterpret_cast<const char*>(userPassword.data()))) 983 { 984 if (ipmi::ccSuccess == 985 ipmiUserSetPrivilegeAccess( 986 ipmiDefaultUserId, 987 static_cast<uint8_t>(ipmi::EChannelID::chanLan1), 988 privAccess, true)) 989 { 990 phosphor::logging::log<phosphor::logging::level::INFO>( 991 "ipmiOEMSetUser2Activation: user created successfully "); 992 return ipmi::responseSuccess(); 993 } 994 } 995 // we need to delete the default user id which added in this command as 996 // password / priv setting is failed. 997 ipmiUserSetUserName(ipmiDefaultUserId, ""); 998 phosphor::logging::log<phosphor::logging::level::ERR>( 999 "ipmiOEMSetUser2Activation: password / priv setting is failed."); 1000 } 1001 else 1002 { 1003 phosphor::logging::log<phosphor::logging::level::ERR>( 1004 "ipmiOEMSetUser2Activation: Setting username failed."); 1005 } 1006 1007 return ipmi::response(ipmi::ccCommandNotAvailable); 1008 } 1009 1010 /** @brief implementes setting password for special user 1011 * @param[in] specialUserIndex 1012 * @param[in] userPassword - new password in 20 bytes 1013 * @returns ipmi completion code. 1014 */ 1015 ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx, 1016 uint8_t specialUserIndex, 1017 std::vector<uint8_t> userPassword) 1018 { 1019 ChannelInfo chInfo; 1020 try 1021 { 1022 getChannelInfo(ctx->channel, chInfo); 1023 } 1024 catch (sdbusplus::exception_t& e) 1025 { 1026 phosphor::logging::log<phosphor::logging::level::ERR>( 1027 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info", 1028 phosphor::logging::entry("MSG: %s", e.description())); 1029 return ipmi::responseUnspecifiedError(); 1030 } 1031 if (chInfo.mediumType != 1032 static_cast<uint8_t>(EChannelMediumType::systemInterface)) 1033 { 1034 phosphor::logging::log<phosphor::logging::level::ERR>( 1035 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS " 1036 "interface"); 1037 return ipmi::responseCommandNotAvailable(); 1038 } 1039 if (specialUserIndex != 0) 1040 { 1041 phosphor::logging::log<phosphor::logging::level::ERR>( 1042 "ipmiOEMSetSpecialUserPassword: Invalid user account"); 1043 return ipmi::responseParmOutOfRange(); 1044 } 1045 constexpr uint8_t minPasswordSizeRequired = 6; 1046 if (userPassword.size() < minPasswordSizeRequired || 1047 userPassword.size() > ipmi::maxIpmi20PasswordSize) 1048 { 1049 return ipmi::responseReqDataLenInvalid(); 1050 } 1051 std::string passwd; 1052 passwd.assign(reinterpret_cast<const char*>(userPassword.data()), 1053 userPassword.size()); 1054 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd)); 1055 } 1056 1057 namespace ledAction 1058 { 1059 using namespace sdbusplus::xyz::openbmc_project::Led::server; 1060 std::map<Physical::Action, uint8_t> actionDbusToIpmi = { 1061 {Physical::Action::Off, 0x00}, 1062 {Physical::Action::On, 0x10}, 1063 {Physical::Action::Blink, 0x01}}; 1064 1065 std::map<uint8_t, std::string> offsetObjPath = { 1066 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}}; 1067 1068 } // namespace ledAction 1069 1070 int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf, 1071 const std::string& objPath, uint8_t& state) 1072 { 1073 try 1074 { 1075 std::string service = getService(bus, intf, objPath); 1076 Value stateValue = 1077 getDbusProperty(bus, service, objPath, intf, "State"); 1078 std::string strState = std::get<std::string>(stateValue); 1079 state = ledAction::actionDbusToIpmi.at( 1080 sdbusplus::xyz::openbmc_project::Led::server::Physical:: 1081 convertActionFromString(strState)); 1082 } 1083 catch (sdbusplus::exception::SdBusError& e) 1084 { 1085 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 1086 return -1; 1087 } 1088 return 0; 1089 } 1090 1091 ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1092 ipmi_request_t request, ipmi_response_t response, 1093 ipmi_data_len_t dataLen, ipmi_context_t context) 1094 { 1095 uint8_t* resp = reinterpret_cast<uint8_t*>(response); 1096 // LED Status 1097 //[1:0] = Reserved 1098 //[3:2] = Status(Amber) 1099 //[5:4] = Status(Green) 1100 //[7:6] = System Identify 1101 // Status definitions: 1102 // 00b = Off 1103 // 01b = Blink 1104 // 10b = On 1105 // 11b = invalid 1106 if (*dataLen != 0) 1107 { 1108 phosphor::logging::log<phosphor::logging::level::ERR>( 1109 "oem_get_led_status: invalid input len!"); 1110 *dataLen = 0; 1111 return IPMI_CC_REQ_DATA_LEN_INVALID; 1112 } 1113 1114 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status"); 1115 *resp = 0; 1116 *dataLen = 0; 1117 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1118 for (auto it = ledAction::offsetObjPath.begin(); 1119 it != ledAction::offsetObjPath.end(); ++it) 1120 { 1121 uint8_t state = 0; 1122 if (-1 == getLEDState(*dbus, ledIntf, it->second, state)) 1123 { 1124 phosphor::logging::log<phosphor::logging::level::ERR>( 1125 "oem_get_led_status: fail to get ID LED status!"); 1126 return IPMI_CC_UNSPECIFIED_ERROR; 1127 } 1128 *resp |= state << it->first; 1129 } 1130 1131 *dataLen = sizeof(*resp); 1132 return IPMI_CC_OK; 1133 } 1134 1135 ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1136 ipmi_request_t request, 1137 ipmi_response_t response, 1138 ipmi_data_len_t dataLen, 1139 ipmi_context_t context) 1140 { 1141 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request); 1142 uint8_t* resp = reinterpret_cast<uint8_t*>(response); 1143 1144 if (*dataLen == 0) 1145 { 1146 phosphor::logging::log<phosphor::logging::level::ERR>( 1147 "CfgHostSerial: invalid input len!", 1148 phosphor::logging::entry("LEN=%d", *dataLen)); 1149 return IPMI_CC_REQ_DATA_LEN_INVALID; 1150 } 1151 1152 switch (req->command) 1153 { 1154 case getHostSerialCfgCmd: 1155 { 1156 if (*dataLen != 1) 1157 { 1158 phosphor::logging::log<phosphor::logging::level::ERR>( 1159 "CfgHostSerial: invalid input len!"); 1160 *dataLen = 0; 1161 return IPMI_CC_REQ_DATA_LEN_INVALID; 1162 } 1163 1164 *dataLen = 0; 1165 1166 boost::process::ipstream is; 1167 std::vector<std::string> data; 1168 std::string line; 1169 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName, 1170 boost::process::std_out > is); 1171 1172 while (c1.running() && std::getline(is, line) && !line.empty()) 1173 { 1174 data.push_back(line); 1175 } 1176 1177 c1.wait(); 1178 if (c1.exit_code()) 1179 { 1180 phosphor::logging::log<phosphor::logging::level::ERR>( 1181 "CfgHostSerial:: error on execute", 1182 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd)); 1183 // Using the default value 1184 *resp = 0; 1185 } 1186 else 1187 { 1188 if (data.size() != 1) 1189 { 1190 phosphor::logging::log<phosphor::logging::level::ERR>( 1191 "CfgHostSerial:: error on read env"); 1192 return IPMI_CC_UNSPECIFIED_ERROR; 1193 } 1194 try 1195 { 1196 unsigned long tmp = std::stoul(data[0]); 1197 if (tmp > std::numeric_limits<uint8_t>::max()) 1198 { 1199 throw std::out_of_range("Out of range"); 1200 } 1201 *resp = static_cast<uint8_t>(tmp); 1202 } 1203 catch (const std::invalid_argument& e) 1204 { 1205 phosphor::logging::log<phosphor::logging::level::ERR>( 1206 "invalid config ", 1207 phosphor::logging::entry("ERR=%s", e.what())); 1208 return IPMI_CC_UNSPECIFIED_ERROR; 1209 } 1210 catch (const std::out_of_range& e) 1211 { 1212 phosphor::logging::log<phosphor::logging::level::ERR>( 1213 "out_of_range config ", 1214 phosphor::logging::entry("ERR=%s", e.what())); 1215 return IPMI_CC_UNSPECIFIED_ERROR; 1216 } 1217 } 1218 1219 *dataLen = 1; 1220 break; 1221 } 1222 case setHostSerialCfgCmd: 1223 { 1224 if (*dataLen != sizeof(CfgHostSerialReq)) 1225 { 1226 phosphor::logging::log<phosphor::logging::level::ERR>( 1227 "CfgHostSerial: invalid input len!"); 1228 *dataLen = 0; 1229 return IPMI_CC_REQ_DATA_LEN_INVALID; 1230 } 1231 1232 *dataLen = 0; 1233 1234 if (req->parameter > HostSerialCfgParamMax) 1235 { 1236 phosphor::logging::log<phosphor::logging::level::ERR>( 1237 "CfgHostSerial: invalid input!"); 1238 return IPMI_CC_INVALID_FIELD_REQUEST; 1239 } 1240 1241 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName, 1242 std::to_string(req->parameter)); 1243 1244 c1.wait(); 1245 if (c1.exit_code()) 1246 { 1247 phosphor::logging::log<phosphor::logging::level::ERR>( 1248 "CfgHostSerial:: error on execute", 1249 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd)); 1250 return IPMI_CC_UNSPECIFIED_ERROR; 1251 } 1252 break; 1253 } 1254 default: 1255 phosphor::logging::log<phosphor::logging::level::ERR>( 1256 "CfgHostSerial: invalid input!"); 1257 *dataLen = 0; 1258 return IPMI_CC_INVALID_FIELD_REQUEST; 1259 } 1260 1261 return IPMI_CC_OK; 1262 } 1263 1264 constexpr const char* thermalModeInterface = 1265 "xyz.openbmc_project.Control.ThermalMode"; 1266 constexpr const char* thermalModePath = 1267 "/xyz/openbmc_project/control/thermal_mode"; 1268 1269 bool getFanProfileInterface( 1270 sdbusplus::bus::bus& bus, 1271 boost::container::flat_map< 1272 std::string, std::variant<std::vector<std::string>, std::string>>& resp) 1273 { 1274 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF, 1275 "GetAll"); 1276 call.append(thermalModeInterface); 1277 try 1278 { 1279 auto data = bus.call(call); 1280 data.read(resp); 1281 } 1282 catch (sdbusplus::exception_t& e) 1283 { 1284 phosphor::logging::log<phosphor::logging::level::ERR>( 1285 "getFanProfileInterface: can't get thermal mode!", 1286 phosphor::logging::entry("ERR=%s", e.what())); 1287 return false; 1288 } 1289 return true; 1290 } 1291 1292 ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1293 ipmi_request_t request, ipmi_response_t response, 1294 ipmi_data_len_t dataLen, ipmi_context_t context) 1295 { 1296 1297 if (*dataLen < 2 || *dataLen > 7) 1298 { 1299 phosphor::logging::log<phosphor::logging::level::ERR>( 1300 "ipmiOEMSetFanConfig: invalid input len!"); 1301 *dataLen = 0; 1302 return IPMI_CC_REQ_DATA_LEN_INVALID; 1303 } 1304 1305 // todo: tell bios to only send first 2 bytes 1306 1307 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request); 1308 boost::container::flat_map< 1309 std::string, std::variant<std::vector<std::string>, std::string>> 1310 profileData; 1311 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1312 if (!getFanProfileInterface(*dbus, profileData)) 1313 { 1314 return IPMI_CC_UNSPECIFIED_ERROR; 1315 } 1316 1317 std::vector<std::string>* supported = 1318 std::get_if<std::vector<std::string>>(&profileData["Supported"]); 1319 if (supported == nullptr) 1320 { 1321 return IPMI_CC_INVALID_FIELD_REQUEST; 1322 } 1323 std::string mode; 1324 if (req->flags & 1325 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode))) 1326 { 1327 bool performanceMode = 1328 (req->flags & (1 << static_cast<uint8_t>( 1329 setFanProfileFlags::performAcousSelect))) > 0; 1330 1331 if (performanceMode) 1332 { 1333 1334 if (std::find(supported->begin(), supported->end(), 1335 "Performance") != supported->end()) 1336 { 1337 mode = "Performance"; 1338 } 1339 } 1340 else 1341 { 1342 1343 if (std::find(supported->begin(), supported->end(), "Acoustic") != 1344 supported->end()) 1345 { 1346 mode = "Acoustic"; 1347 } 1348 } 1349 if (mode.empty()) 1350 { 1351 return IPMI_CC_INVALID_FIELD_REQUEST; 1352 } 1353 setDbusProperty(*dbus, settingsBusName, thermalModePath, 1354 thermalModeInterface, "Current", mode); 1355 } 1356 1357 return IPMI_CC_OK; 1358 } 1359 1360 ipmi::RspType<uint8_t, // profile support map 1361 uint8_t, // fan control profile enable 1362 uint8_t, // flags 1363 uint32_t // dimm presence bit map 1364 > 1365 ipmiOEMGetFanConfig(uint8_t dimmGroupId) 1366 { 1367 boost::container::flat_map< 1368 std::string, std::variant<std::vector<std::string>, std::string>> 1369 profileData; 1370 1371 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1372 if (!getFanProfileInterface(*dbus, profileData)) 1373 { 1374 return ipmi::responseResponseError(); 1375 } 1376 1377 std::string* current = std::get_if<std::string>(&profileData["Current"]); 1378 1379 if (current == nullptr) 1380 { 1381 phosphor::logging::log<phosphor::logging::level::ERR>( 1382 "ipmiOEMGetFanConfig: can't get current mode!"); 1383 return ipmi::responseResponseError(); 1384 } 1385 bool performance = (*current == "Performance"); 1386 1387 uint8_t flags = 0; 1388 if (performance) 1389 { 1390 flags |= 1 << 2; 1391 } 1392 1393 return ipmi::responseSuccess(0, 0, flags, 0); 1394 } 1395 constexpr const char* cfmLimitSettingPath = 1396 "/xyz/openbmc_project/control/cfm_limit"; 1397 constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit"; 1398 constexpr const size_t legacyExitAirSensorNumber = 0x2e; 1399 constexpr const size_t legacyPCHSensorNumber = 0x22; 1400 constexpr const char* exitAirPathName = "Exit_Air"; 1401 constexpr const char* pchPathName = "SSB_Temp"; 1402 constexpr const char* pidConfigurationIface = 1403 "xyz.openbmc_project.Configuration.Pid"; 1404 1405 static std::string getConfigPath(const std::string& name) 1406 { 1407 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1408 auto method = 1409 dbus->new_method_call("xyz.openbmc_project.ObjectMapper", 1410 "/xyz/openbmc_project/object_mapper", 1411 "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1412 1413 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface}); 1414 std::string path; 1415 GetSubTreeType resp; 1416 try 1417 { 1418 auto reply = dbus->call(method); 1419 reply.read(resp); 1420 } 1421 catch (sdbusplus::exception_t&) 1422 { 1423 phosphor::logging::log<phosphor::logging::level::ERR>( 1424 "ipmiOEMGetFscParameter: mapper error"); 1425 }; 1426 auto config = 1427 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) { 1428 return pair.first.find(name) != std::string::npos; 1429 }); 1430 if (config != resp.end()) 1431 { 1432 path = std::move(config->first); 1433 } 1434 return path; 1435 } 1436 1437 // flat map to make alphabetical 1438 static boost::container::flat_map<std::string, PropertyMap> getPidConfigs() 1439 { 1440 boost::container::flat_map<std::string, PropertyMap> ret; 1441 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1442 auto method = 1443 dbus->new_method_call("xyz.openbmc_project.ObjectMapper", 1444 "/xyz/openbmc_project/object_mapper", 1445 "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1446 1447 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface}); 1448 GetSubTreeType resp; 1449 1450 try 1451 { 1452 auto reply = dbus->call(method); 1453 reply.read(resp); 1454 } 1455 catch (sdbusplus::exception_t&) 1456 { 1457 phosphor::logging::log<phosphor::logging::level::ERR>( 1458 "getFanConfigPaths: mapper error"); 1459 }; 1460 for (const auto& [path, objects] : resp) 1461 { 1462 if (objects.empty()) 1463 { 1464 continue; // should be impossible 1465 } 1466 1467 try 1468 { 1469 ret.emplace(path, 1470 getAllDbusProperties(*dbus, objects[0].first, path, 1471 pidConfigurationIface)); 1472 } 1473 catch (sdbusplus::exception_t& e) 1474 { 1475 phosphor::logging::log<phosphor::logging::level::ERR>( 1476 "getPidConfigs: can't get DbusProperties!", 1477 phosphor::logging::entry("ERR=%s", e.what())); 1478 } 1479 } 1480 return ret; 1481 } 1482 1483 ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void) 1484 { 1485 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs(); 1486 if (data.empty()) 1487 { 1488 return ipmi::responseResponseError(); 1489 } 1490 uint8_t minOffset = std::numeric_limits<uint8_t>::max(); 1491 for (const auto& [_, pid] : data) 1492 { 1493 auto findClass = pid.find("Class"); 1494 if (findClass == pid.end()) 1495 { 1496 phosphor::logging::log<phosphor::logging::level::ERR>( 1497 "ipmiOEMGetFscParameter: found illegal pid " 1498 "configurations"); 1499 return ipmi::responseResponseError(); 1500 } 1501 std::string type = std::get<std::string>(findClass->second); 1502 if (type == "fan") 1503 { 1504 auto findOutLimit = pid.find("OutLimitMin"); 1505 if (findOutLimit == pid.end()) 1506 { 1507 phosphor::logging::log<phosphor::logging::level::ERR>( 1508 "ipmiOEMGetFscParameter: found illegal pid " 1509 "configurations"); 1510 return ipmi::responseResponseError(); 1511 } 1512 // get the min out of all the offsets 1513 minOffset = std::min( 1514 minOffset, 1515 static_cast<uint8_t>(std::get<double>(findOutLimit->second))); 1516 } 1517 } 1518 if (minOffset == std::numeric_limits<uint8_t>::max()) 1519 { 1520 phosphor::logging::log<phosphor::logging::level::ERR>( 1521 "ipmiOEMGetFscParameter: found no fan configurations!"); 1522 return ipmi::responseResponseError(); 1523 } 1524 1525 return ipmi::responseSuccess(minOffset); 1526 } 1527 1528 ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset) 1529 { 1530 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs(); 1531 if (data.empty()) 1532 { 1533 1534 phosphor::logging::log<phosphor::logging::level::ERR>( 1535 "ipmiOEMSetFanSpeedOffset: found no pid configurations!"); 1536 return ipmi::responseResponseError(); 1537 } 1538 1539 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1540 bool found = false; 1541 for (const auto& [path, pid] : data) 1542 { 1543 auto findClass = pid.find("Class"); 1544 if (findClass == pid.end()) 1545 { 1546 1547 phosphor::logging::log<phosphor::logging::level::ERR>( 1548 "ipmiOEMSetFanSpeedOffset: found illegal pid " 1549 "configurations"); 1550 return ipmi::responseResponseError(); 1551 } 1552 std::string type = std::get<std::string>(findClass->second); 1553 if (type == "fan") 1554 { 1555 auto findOutLimit = pid.find("OutLimitMin"); 1556 if (findOutLimit == pid.end()) 1557 { 1558 1559 phosphor::logging::log<phosphor::logging::level::ERR>( 1560 "ipmiOEMSetFanSpeedOffset: found illegal pid " 1561 "configurations"); 1562 return ipmi::responseResponseError(); 1563 } 1564 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", 1565 path, pidConfigurationIface, "OutLimitMin", 1566 static_cast<double>(offset)); 1567 found = true; 1568 } 1569 } 1570 if (!found) 1571 { 1572 phosphor::logging::log<phosphor::logging::level::ERR>( 1573 "ipmiOEMSetFanSpeedOffset: set no fan offsets"); 1574 return ipmi::responseResponseError(); 1575 } 1576 1577 return ipmi::responseSuccess(); 1578 } 1579 1580 ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1, 1581 uint8_t param2) 1582 { 1583 constexpr const size_t disableLimiting = 0x0; 1584 1585 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1586 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol)) 1587 { 1588 std::string pathName; 1589 if (param1 == legacyExitAirSensorNumber) 1590 { 1591 pathName = exitAirPathName; 1592 } 1593 else if (param1 == legacyPCHSensorNumber) 1594 { 1595 pathName = pchPathName; 1596 } 1597 else 1598 { 1599 return ipmi::responseParmOutOfRange(); 1600 } 1601 std::string path = getConfigPath(pathName); 1602 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path, 1603 pidConfigurationIface, "SetPoint", 1604 static_cast<double>(param2)); 1605 return ipmi::responseSuccess(); 1606 } 1607 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm)) 1608 { 1609 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8); 1610 1611 // must be greater than 50 based on eps 1612 if (cfm < 50 && cfm != disableLimiting) 1613 { 1614 return ipmi::responseParmOutOfRange(); 1615 } 1616 1617 try 1618 { 1619 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath, 1620 cfmLimitIface, "Limit", 1621 static_cast<double>(cfm)); 1622 } 1623 catch (sdbusplus::exception_t& e) 1624 { 1625 phosphor::logging::log<phosphor::logging::level::ERR>( 1626 "ipmiOEMSetFscParameter: can't set cfm setting!", 1627 phosphor::logging::entry("ERR=%s", e.what())); 1628 return ipmi::responseResponseError(); 1629 } 1630 return ipmi::responseSuccess(); 1631 } 1632 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm)) 1633 { 1634 constexpr const size_t maxDomainCount = 8; 1635 uint8_t requestedDomainMask = param1; 1636 boost::container::flat_map data = getPidConfigs(); 1637 if (data.empty()) 1638 { 1639 1640 phosphor::logging::log<phosphor::logging::level::ERR>( 1641 "ipmiOEMSetFscParameter: found no pid configurations!"); 1642 return ipmi::responseResponseError(); 1643 } 1644 size_t count = 0; 1645 for (const auto& [path, pid] : data) 1646 { 1647 auto findClass = pid.find("Class"); 1648 if (findClass == pid.end()) 1649 { 1650 1651 phosphor::logging::log<phosphor::logging::level::ERR>( 1652 "ipmiOEMSetFscParameter: found illegal pid " 1653 "configurations"); 1654 return ipmi::responseResponseError(); 1655 } 1656 std::string type = std::get<std::string>(findClass->second); 1657 if (type == "fan") 1658 { 1659 if (requestedDomainMask & (1 << count)) 1660 { 1661 ipmi::setDbusProperty( 1662 *dbus, "xyz.openbmc_project.EntityManager", path, 1663 pidConfigurationIface, "OutLimitMax", 1664 static_cast<double>(param2)); 1665 } 1666 count++; 1667 } 1668 } 1669 return ipmi::responseSuccess(); 1670 } 1671 else 1672 { 1673 // todo other command parts possibly 1674 // tcontrol is handled in peci now 1675 // fan speed offset not implemented yet 1676 // domain pwm limit not implemented 1677 return ipmi::responseParmOutOfRange(); 1678 } 1679 } 1680 1681 ipmi::RspType< 1682 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>> 1683 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param) 1684 { 1685 constexpr uint8_t legacyDefaultSetpoint = -128; 1686 1687 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1688 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol)) 1689 { 1690 if (!param) 1691 { 1692 return ipmi::responseReqDataLenInvalid(); 1693 } 1694 1695 std::string pathName; 1696 1697 if (*param == legacyExitAirSensorNumber) 1698 { 1699 pathName = exitAirPathName; 1700 } 1701 else if (*param == legacyPCHSensorNumber) 1702 { 1703 pathName = pchPathName; 1704 } 1705 else 1706 { 1707 return ipmi::responseParmOutOfRange(); 1708 } 1709 1710 uint8_t setpoint = legacyDefaultSetpoint; 1711 std::string path = getConfigPath(pathName); 1712 if (path.size()) 1713 { 1714 Value val = ipmi::getDbusProperty( 1715 *dbus, "xyz.openbmc_project.EntityManager", path, 1716 pidConfigurationIface, "SetPoint"); 1717 setpoint = std::floor(std::get<double>(val) + 0.5); 1718 } 1719 1720 // old implementation used to return the "default" and current, we 1721 // don't make the default readily available so just make both the 1722 // same 1723 1724 return ipmi::responseSuccess( 1725 std::array<uint8_t, 2>{setpoint, setpoint}); 1726 } 1727 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm)) 1728 { 1729 constexpr const size_t maxDomainCount = 8; 1730 1731 if (!param) 1732 { 1733 return ipmi::responseReqDataLenInvalid(); 1734 } 1735 uint8_t requestedDomain = *param; 1736 if (requestedDomain >= maxDomainCount) 1737 { 1738 return ipmi::responseInvalidFieldRequest(); 1739 } 1740 1741 boost::container::flat_map data = getPidConfigs(); 1742 if (data.empty()) 1743 { 1744 phosphor::logging::log<phosphor::logging::level::ERR>( 1745 "ipmiOEMGetFscParameter: found no pid configurations!"); 1746 return ipmi::responseResponseError(); 1747 } 1748 size_t count = 0; 1749 for (const auto& [_, pid] : data) 1750 { 1751 auto findClass = pid.find("Class"); 1752 if (findClass == pid.end()) 1753 { 1754 phosphor::logging::log<phosphor::logging::level::ERR>( 1755 "ipmiOEMGetFscParameter: found illegal pid " 1756 "configurations"); 1757 return ipmi::responseResponseError(); 1758 } 1759 std::string type = std::get<std::string>(findClass->second); 1760 if (type == "fan") 1761 { 1762 if (requestedDomain == count) 1763 { 1764 auto findOutLimit = pid.find("OutLimitMax"); 1765 if (findOutLimit == pid.end()) 1766 { 1767 phosphor::logging::log<phosphor::logging::level::ERR>( 1768 "ipmiOEMGetFscParameter: found illegal pid " 1769 "configurations"); 1770 return ipmi::responseResponseError(); 1771 } 1772 1773 return ipmi::responseSuccess( 1774 static_cast<uint8_t>(std::floor( 1775 std::get<double>(findOutLimit->second) + 0.5))); 1776 } 1777 else 1778 { 1779 count++; 1780 } 1781 } 1782 } 1783 1784 return ipmi::responseInvalidFieldRequest(); 1785 } 1786 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm)) 1787 { 1788 1789 /* 1790 DataLen should be 1, but host is sending us an extra bit. As the 1791 previous behavior didn't seem to prevent this, ignore the check for 1792 now. 1793 1794 if (param) 1795 { 1796 phosphor::logging::log<phosphor::logging::level::ERR>( 1797 "ipmiOEMGetFscParameter: invalid input len!"); 1798 return IPMI_CC_REQ_DATA_LEN_INVALID; 1799 } 1800 */ 1801 Value cfmLimit; 1802 Value cfmMaximum; 1803 try 1804 { 1805 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName, 1806 cfmLimitSettingPath, cfmLimitIface, 1807 "Limit"); 1808 cfmMaximum = ipmi::getDbusProperty( 1809 *dbus, "xyz.openbmc_project.ExitAirTempSensor", 1810 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit"); 1811 } 1812 catch (sdbusplus::exception_t& e) 1813 { 1814 phosphor::logging::log<phosphor::logging::level::ERR>( 1815 "ipmiOEMGetFscParameter: can't get cfm setting!", 1816 phosphor::logging::entry("ERR=%s", e.what())); 1817 return ipmi::responseResponseError(); 1818 } 1819 1820 double cfmMax = std::get<double>(cfmMaximum); 1821 double cfmLim = std::get<double>(cfmLimit); 1822 1823 cfmLim = std::floor(cfmLim + 0.5); 1824 cfmMax = std::floor(cfmMax + 0.5); 1825 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim); 1826 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax); 1827 1828 return ipmi::responseSuccess( 1829 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp}); 1830 } 1831 1832 else 1833 { 1834 // todo other command parts possibly 1835 // domain pwm limit not implemented 1836 return ipmi::responseParmOutOfRange(); 1837 } 1838 } 1839 1840 using crConfigVariant = 1841 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>; 1842 1843 int setCRConfig(ipmi::Context::ptr ctx, const std::string& property, 1844 const crConfigVariant& value, 1845 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT) 1846 { 1847 boost::system::error_code ec; 1848 ctx->bus->yield_method_call<void>( 1849 *(ctx->yield), ec, "xyz.openbmc_project.Settings", 1850 "/xyz/openbmc_project/control/power_supply_redundancy", 1851 "org.freedesktop.DBus.Properties", "Set", 1852 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value); 1853 if (ec) 1854 { 1855 phosphor::logging::log<phosphor::logging::level::ERR>( 1856 "Failed to set dbus property to cold redundancy"); 1857 return -1; 1858 } 1859 1860 return 0; 1861 } 1862 1863 int getCRConfig(ipmi::Context::ptr ctx, const std::string& property, 1864 crConfigVariant& value, 1865 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT) 1866 { 1867 boost::system::error_code ec; 1868 value = ctx->bus->yield_method_call<crConfigVariant>( 1869 *(ctx->yield), ec, "xyz.openbmc_project.Settings", 1870 "/xyz/openbmc_project/control/power_supply_redundancy", 1871 "org.freedesktop.DBus.Properties", "Get", 1872 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property); 1873 if (ec) 1874 { 1875 phosphor::logging::log<phosphor::logging::level::ERR>( 1876 "Failed to get dbus property to cold redundancy"); 1877 return -1; 1878 } 1879 return 0; 1880 } 1881 1882 uint8_t getPSUCount(void) 1883 { 1884 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1885 ipmi::Value num; 1886 try 1887 { 1888 num = ipmi::getDbusProperty( 1889 *dbus, "xyz.openbmc_project.PSURedundancy", 1890 "/xyz/openbmc_project/control/power_supply_redundancy", 1891 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber"); 1892 } 1893 catch (sdbusplus::exception_t& e) 1894 { 1895 phosphor::logging::log<phosphor::logging::level::ERR>( 1896 "Failed to get PSUNumber property from dbus interface"); 1897 return 0; 1898 } 1899 uint8_t* pNum = std::get_if<uint8_t>(&num); 1900 if (!pNum) 1901 { 1902 phosphor::logging::log<phosphor::logging::level::ERR>( 1903 "Error to get PSU Number"); 1904 return 0; 1905 } 1906 return *pNum; 1907 } 1908 1909 bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num) 1910 { 1911 if (conf.size() < num) 1912 { 1913 phosphor::logging::log<phosphor::logging::level::ERR>( 1914 "Invalid PSU Ranking"); 1915 return false; 1916 } 1917 std::set<uint8_t> confSet; 1918 for (uint8_t i = 0; i < num; i++) 1919 { 1920 if (conf[i] > num) 1921 { 1922 phosphor::logging::log<phosphor::logging::level::ERR>( 1923 "PSU Ranking is larger than current PSU number"); 1924 return false; 1925 } 1926 confSet.emplace(conf[i]); 1927 } 1928 1929 if (confSet.size() != num) 1930 { 1931 phosphor::logging::log<phosphor::logging::level::ERR>( 1932 "duplicate PSU Ranking"); 1933 return false; 1934 } 1935 return true; 1936 } 1937 1938 enum class crParameter 1939 { 1940 crStatus = 0, 1941 crFeature = 1, 1942 rotationFeature = 2, 1943 rotationAlgo = 3, 1944 rotationPeriod = 4, 1945 numOfPSU = 5 1946 }; 1947 1948 constexpr ipmi::Cc ccParameterNotSupported = 0x80; 1949 static const constexpr uint32_t oneDay = 0x15180; 1950 static const constexpr uint32_t oneMonth = 0xf53700; 1951 static const constexpr uint8_t userSpecific = 0x01; 1952 static const constexpr uint8_t crSetCompleted = 0; 1953 ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx, 1954 uint8_t parameter, 1955 ipmi::message::Payload& payload) 1956 { 1957 switch (static_cast<crParameter>(parameter)) 1958 { 1959 case crParameter::crFeature: 1960 { 1961 uint8_t param1; 1962 if (payload.unpack(param1) || !payload.fullyUnpacked()) 1963 { 1964 return ipmi::responseReqDataLenInvalid(); 1965 } 1966 // ColdRedundancy Enable can only be true or flase 1967 if (param1 > 1) 1968 { 1969 return ipmi::responseInvalidFieldRequest(); 1970 } 1971 if (setCRConfig(ctx, "ColdRedundancyEnabled", 1972 static_cast<bool>(param1))) 1973 { 1974 return ipmi::responseResponseError(); 1975 } 1976 break; 1977 } 1978 case crParameter::rotationFeature: 1979 { 1980 uint8_t param1; 1981 if (payload.unpack(param1) || !payload.fullyUnpacked()) 1982 { 1983 return ipmi::responseReqDataLenInvalid(); 1984 } 1985 // Rotation Enable can only be true or false 1986 if (param1 > 1) 1987 { 1988 return ipmi::responseInvalidFieldRequest(); 1989 } 1990 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1))) 1991 { 1992 return ipmi::responseResponseError(); 1993 } 1994 break; 1995 } 1996 case crParameter::rotationAlgo: 1997 { 1998 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific 1999 std::string algoName; 2000 uint8_t param1; 2001 if (payload.unpack(param1)) 2002 { 2003 return ipmi::responseReqDataLenInvalid(); 2004 } 2005 switch (param1) 2006 { 2007 case 0: 2008 algoName = "xyz.openbmc_project.Control." 2009 "PowerSupplyRedundancy.Algo.bmcSpecific"; 2010 break; 2011 case 1: 2012 algoName = "xyz.openbmc_project.Control." 2013 "PowerSupplyRedundancy.Algo.userSpecific"; 2014 break; 2015 default: 2016 return ipmi::responseInvalidFieldRequest(); 2017 } 2018 if (setCRConfig(ctx, "RotationAlgorithm", algoName)) 2019 { 2020 return ipmi::responseResponseError(); 2021 } 2022 2023 uint8_t numberOfPSU = getPSUCount(); 2024 if (!numberOfPSU) 2025 { 2026 return ipmi::responseResponseError(); 2027 } 2028 std::vector<uint8_t> rankOrder; 2029 2030 if (param1 == userSpecific) 2031 { 2032 if (payload.unpack(rankOrder) || !payload.fullyUnpacked()) 2033 { 2034 ipmi::responseReqDataLenInvalid(); 2035 } 2036 if (rankOrder.size() < numberOfPSU) 2037 { 2038 return ipmi::responseReqDataLenInvalid(); 2039 } 2040 2041 if (!validateCRAlgo(rankOrder, numberOfPSU)) 2042 { 2043 return ipmi::responseInvalidFieldRequest(); 2044 } 2045 } 2046 else 2047 { 2048 if (rankOrder.size() > 0) 2049 { 2050 return ipmi::responseReqDataLenInvalid(); 2051 } 2052 for (uint8_t i = 1; i <= numberOfPSU; i++) 2053 { 2054 rankOrder.emplace_back(i); 2055 } 2056 } 2057 if (setCRConfig(ctx, "RotationRankOrder", rankOrder)) 2058 { 2059 return ipmi::responseResponseError(); 2060 } 2061 break; 2062 } 2063 case crParameter::rotationPeriod: 2064 { 2065 // Minimum Rotation period is One day (86400 seconds) and Max 2066 // Rotation Period is 6 month (0xf53700 seconds) 2067 uint32_t period; 2068 if (payload.unpack(period) || !payload.fullyUnpacked()) 2069 { 2070 return ipmi::responseReqDataLenInvalid(); 2071 } 2072 if ((period < oneDay) || (period > oneMonth)) 2073 { 2074 return ipmi::responseInvalidFieldRequest(); 2075 } 2076 if (setCRConfig(ctx, "PeriodOfRotation", period)) 2077 { 2078 return ipmi::responseResponseError(); 2079 } 2080 break; 2081 } 2082 default: 2083 { 2084 return ipmi::response(ccParameterNotSupported); 2085 } 2086 } 2087 2088 // TODO Halfwidth needs to set SetInProgress 2089 if (setCRConfig(ctx, "ColdRedundancyStatus", 2090 std::string("xyz.openbmc_project.Control." 2091 "PowerSupplyRedundancy.Status.completed"))) 2092 { 2093 return ipmi::responseResponseError(); 2094 } 2095 return ipmi::responseSuccess(crSetCompleted); 2096 } 2097 2098 ipmi::RspType<std::variant<uint8_t, uint32_t, std::array<uint8_t, 5>>> 2099 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter) 2100 { 2101 crConfigVariant value; 2102 switch (static_cast<crParameter>(parameter)) 2103 { 2104 case crParameter::crStatus: 2105 { 2106 if (getCRConfig(ctx, "ColdRedundancyStatus", value)) 2107 { 2108 return ipmi::responseResponseError(); 2109 } 2110 std::string* pStatus = std::get_if<std::string>(&value); 2111 if (!pStatus) 2112 { 2113 phosphor::logging::log<phosphor::logging::level::ERR>( 2114 "Error to get ColdRedundancyStatus property"); 2115 return ipmi::responseResponseError(); 2116 } 2117 namespace server = sdbusplus::xyz::openbmc_project::Control::server; 2118 auto status = 2119 server::PowerSupplyRedundancy::convertStatusFromString( 2120 *pStatus); 2121 switch (status) 2122 { 2123 case server::PowerSupplyRedundancy::Status::inProgress: 2124 return ipmi::responseSuccess(static_cast<uint8_t>(0)); 2125 2126 case server::PowerSupplyRedundancy::Status::completed: 2127 return ipmi::responseSuccess(static_cast<uint8_t>(1)); 2128 default: 2129 phosphor::logging::log<phosphor::logging::level::ERR>( 2130 "Error to get valid status"); 2131 return ipmi::responseResponseError(); 2132 } 2133 } 2134 case crParameter::crFeature: 2135 { 2136 if (getCRConfig(ctx, "ColdRedundancyEnabled", value)) 2137 { 2138 return ipmi::responseResponseError(); 2139 } 2140 bool* pResponse = std::get_if<bool>(&value); 2141 if (!pResponse) 2142 { 2143 phosphor::logging::log<phosphor::logging::level::ERR>( 2144 "Error to get ColdRedundancyEnable property"); 2145 return ipmi::responseResponseError(); 2146 } 2147 2148 return ipmi::responseSuccess(static_cast<uint8_t>(*pResponse)); 2149 } 2150 case crParameter::rotationFeature: 2151 { 2152 if (getCRConfig(ctx, "RotationEnabled", value)) 2153 { 2154 return ipmi::responseResponseError(); 2155 } 2156 bool* pResponse = std::get_if<bool>(&value); 2157 if (!pResponse) 2158 { 2159 phosphor::logging::log<phosphor::logging::level::ERR>( 2160 "Error to get RotationEnabled property"); 2161 return ipmi::responseResponseError(); 2162 } 2163 return ipmi::responseSuccess(static_cast<uint8_t>(*pResponse)); 2164 } 2165 case crParameter::rotationAlgo: 2166 { 2167 if (getCRConfig(ctx, "RotationAlgorithm", value)) 2168 { 2169 return ipmi::responseResponseError(); 2170 } 2171 2172 std::string* pAlgo = std::get_if<std::string>(&value); 2173 if (!pAlgo) 2174 { 2175 phosphor::logging::log<phosphor::logging::level::ERR>( 2176 "Error to get RotationAlgorithm property"); 2177 return ipmi::responseResponseError(); 2178 } 2179 std::array<uint8_t, 5> response = {0, 0, 0, 0, 0}; 2180 namespace server = sdbusplus::xyz::openbmc_project::Control::server; 2181 auto algo = 2182 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo); 2183 switch (algo) 2184 { 2185 case server::PowerSupplyRedundancy::Algo::bmcSpecific: 2186 response[0] = 0; 2187 break; 2188 case server::PowerSupplyRedundancy::Algo::userSpecific: 2189 response[0] = 1; 2190 break; 2191 default: 2192 phosphor::logging::log<phosphor::logging::level::ERR>( 2193 "Error to get valid algo"); 2194 return ipmi::responseResponseError(); 2195 } 2196 2197 if (getCRConfig(ctx, "RotationRankOrder", value)) 2198 { 2199 return ipmi::responseResponseError(); 2200 } 2201 std::vector<uint8_t>* pResponse = 2202 std::get_if<std::vector<uint8_t>>(&value); 2203 if (!pResponse) 2204 { 2205 phosphor::logging::log<phosphor::logging::level::ERR>( 2206 "Error to get RotationRankOrder property"); 2207 return ipmi::responseResponseError(); 2208 } 2209 if (pResponse->size() + 1 > response.size()) 2210 { 2211 phosphor::logging::log<phosphor::logging::level::ERR>( 2212 "Incorrect size of RotationAlgorithm property"); 2213 return ipmi::responseResponseError(); 2214 } 2215 std::copy(pResponse->begin(), pResponse->end(), 2216 response.begin() + 1); 2217 return ipmi::responseSuccess(response); 2218 } 2219 case crParameter::rotationPeriod: 2220 { 2221 if (getCRConfig(ctx, "PeriodOfRotation", value)) 2222 { 2223 return ipmi::responseResponseError(); 2224 } 2225 uint32_t* pResponse = std::get_if<uint32_t>(&value); 2226 if (!pResponse) 2227 { 2228 phosphor::logging::log<phosphor::logging::level::ERR>( 2229 "Error to get RotationAlgorithm property"); 2230 return ipmi::responseResponseError(); 2231 } 2232 return ipmi::responseSuccess(*pResponse); 2233 } 2234 case crParameter::numOfPSU: 2235 { 2236 uint8_t numberOfPSU = getPSUCount(); 2237 if (!numberOfPSU) 2238 { 2239 return ipmi::responseResponseError(); 2240 } 2241 return ipmi::responseSuccess(numberOfPSU); 2242 } 2243 default: 2244 { 2245 return ipmi::response(ccParameterNotSupported); 2246 } 2247 } 2248 } 2249 2250 ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType, 2251 uint8_t faultState, 2252 uint8_t faultGroup, 2253 std::array<uint8_t, 8>& ledStateData) 2254 { 2255 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager"; 2256 static constexpr const char* intf = "xyz.openbmc_project.EntityManager"; 2257 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max); 2258 static const std::array<std::string, maxFaultType> faultNames = { 2259 "faultFan", "faultTemp", "faultPower", 2260 "faultDriveSlot", "faultSoftware", "faultMemory"}; 2261 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio"; 2262 static constexpr const char* postfixValue = "/value"; 2263 2264 constexpr uint8_t maxFaultSource = 0x4; 2265 constexpr uint8_t skipLEDs = 0xFF; 2266 constexpr uint8_t pinSize = 64; 2267 constexpr uint8_t groupSize = 16; 2268 2269 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF); 2270 uint64_t resFIndex = 0; 2271 std::string resFType; 2272 std::string service; 2273 ObjectValueTree valueTree; 2274 2275 // Validate the source, fault type 2276 if ((sourceId >= maxFaultSource) || 2277 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) || 2278 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) || 2279 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup))) 2280 { 2281 return ipmi::responseParmOutOfRange(); 2282 } 2283 2284 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2285 try 2286 { 2287 service = getService(*dbus, intf, objpath); 2288 valueTree = getManagedObjects(*dbus, service, "/"); 2289 } 2290 catch (const std::exception& e) 2291 { 2292 phosphor::logging::log<phosphor::logging::level::ERR>( 2293 "No object implements interface", 2294 phosphor::logging::entry("SERVICE=%s", service.c_str()), 2295 phosphor::logging::entry("INTF=%s", intf)); 2296 return ipmi::responseResponseError(); 2297 } 2298 2299 if (valueTree.empty()) 2300 { 2301 phosphor::logging::log<phosphor::logging::level::ERR>( 2302 "No object implements interface", 2303 phosphor::logging::entry("INTF=%s", intf)); 2304 return ipmi::responseResponseError(); 2305 } 2306 2307 for (const auto& item : valueTree) 2308 { 2309 // find LedFault configuration 2310 auto interface = 2311 item.second.find("xyz.openbmc_project.Configuration.LedFault"); 2312 if (interface == item.second.end()) 2313 { 2314 continue; 2315 } 2316 2317 // find matched fault type: faultMemmory / faultFan 2318 // find LedGpioPins/FaultIndex configuration 2319 auto propertyFaultType = interface->second.find("FaultType"); 2320 auto propertyFIndex = interface->second.find("FaultIndex"); 2321 auto ledIndex = interface->second.find("LedGpioPins"); 2322 2323 if (propertyFaultType == interface->second.end() || 2324 propertyFIndex == interface->second.end() || 2325 ledIndex == interface->second.end()) 2326 { 2327 continue; 2328 } 2329 2330 try 2331 { 2332 Value valIndex = propertyFIndex->second; 2333 resFIndex = std::get<uint64_t>(valIndex); 2334 2335 Value valFType = propertyFaultType->second; 2336 resFType = std::get<std::string>(valFType); 2337 } 2338 catch (const std::bad_variant_access& e) 2339 { 2340 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 2341 return ipmi::responseResponseError(); 2342 } 2343 // find the matched requested fault type: faultMemmory or faultFan 2344 if (resFType != faultNames[faultType]) 2345 { 2346 continue; 2347 } 2348 2349 // read LedGpioPins data 2350 std::vector<uint64_t> ledgpios; 2351 std::variant<std::vector<uint64_t>> message; 2352 2353 auto method = dbus->new_method_call( 2354 service.c_str(), (std::string(item.first)).c_str(), 2355 "org.freedesktop.DBus.Properties", "Get"); 2356 2357 method.append("xyz.openbmc_project.Configuration.LedFault", 2358 "LedGpioPins"); 2359 2360 try 2361 { 2362 auto reply = dbus->call(method); 2363 reply.read(message); 2364 ledgpios = std::get<std::vector<uint64_t>>(message); 2365 } 2366 catch (std::exception& e) 2367 { 2368 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 2369 return ipmi::responseResponseError(); 2370 } 2371 2372 // Check the size to be sure it will never overflow on groupSize 2373 if (ledgpios.size() > groupSize) 2374 { 2375 phosphor::logging::log<phosphor::logging::level::ERR>( 2376 "Fault gpio Pins out of range!"); 2377 return ipmi::responseParmOutOfRange(); 2378 } 2379 // Store data, according to command data bit index order 2380 for (int i = 0; i < ledgpios.size(); i++) 2381 { 2382 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i]; 2383 } 2384 } 2385 2386 switch (RemoteFaultType(faultType)) 2387 { 2388 case (RemoteFaultType::fan): 2389 case (RemoteFaultType::memory): 2390 { 2391 if (faultGroup == skipLEDs) 2392 { 2393 return ipmi::responseSuccess(); 2394 } 2395 2396 uint64_t ledState = 0; 2397 // calculate led state bit filed count, each byte has 8bits 2398 // the maximum bits will be 8 * 8 bits 2399 constexpr uint8_t size = sizeof(ledStateData) * 8; 2400 for (int i = 0; i < sizeof(ledStateData); i++) 2401 { 2402 ledState = (uint64_t)(ledState << 8); 2403 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]); 2404 } 2405 2406 std::bitset<size> ledStateBits(ledState); 2407 std::string gpioValue; 2408 for (int i = 0; i < size; i++) 2409 { // skip invalid value 2410 if (ledFaultPins[i] == 0xFFFF) 2411 { 2412 continue; 2413 } 2414 2415 std::string device = sysGpioPath + 2416 std::to_string(ledFaultPins[i]) + 2417 postfixValue; 2418 std::fstream gpioFile; 2419 2420 gpioFile.open(device, std::ios::out); 2421 2422 if (!gpioFile.good()) 2423 { 2424 phosphor::logging::log<phosphor::logging::level::ERR>( 2425 "Not Find Led Gpio Device!", 2426 phosphor::logging::entry("DEVICE=%s", device.c_str())); 2427 return ipmi::responseResponseError(); 2428 } 2429 gpioFile << std::to_string( 2430 static_cast<uint8_t>(ledStateBits[i])); 2431 gpioFile.close(); 2432 } 2433 break; 2434 } 2435 default: 2436 { 2437 // now only support two fault types 2438 return ipmi::responseParmOutOfRange(); 2439 } 2440 } 2441 2442 return ipmi::responseSuccess(); 2443 } 2444 2445 ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId() 2446 { 2447 uint8_t prodId = 0; 2448 try 2449 { 2450 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2451 const DbusObjectInfo& object = getDbusObject( 2452 *dbus, "xyz.openbmc_project.Inventory.Item.Board", 2453 "/xyz/openbmc_project/inventory/system/board/", "Baseboard"); 2454 const Value& propValue = getDbusProperty( 2455 *dbus, object.second, object.first, 2456 "xyz.openbmc_project.Inventory.Item.Board", "ProductId"); 2457 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue)); 2458 } 2459 catch (std::exception& e) 2460 { 2461 phosphor::logging::log<phosphor::logging::level::ERR>( 2462 "ipmiOEMReadBoardProductId: Product ID read failed!", 2463 phosphor::logging::entry("ERR=%s", e.what())); 2464 } 2465 return ipmi::responseSuccess(prodId); 2466 } 2467 2468 /** @brief implements the get security mode command 2469 * @param ctx - ctx pointer 2470 * 2471 * @returns IPMI completion code with following data 2472 * - restriction mode value - As specified in 2473 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml 2474 * - special mode value - As specified in 2475 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml 2476 */ 2477 ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx) 2478 { 2479 namespace securityNameSpace = 2480 sdbusplus::xyz::openbmc_project::Control::Security::server; 2481 uint8_t restrictionModeValue = 0; 2482 uint8_t specialModeValue = 0; 2483 2484 boost::system::error_code ec; 2485 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>( 2486 *ctx->yield, ec, restricionModeService, restricionModeBasePath, 2487 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf, 2488 restricionModeProperty); 2489 if (ec) 2490 { 2491 phosphor::logging::log<phosphor::logging::level::ERR>( 2492 "ipmiGetSecurityMode: failed to get RestrictionMode property", 2493 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2494 return ipmi::responseUnspecifiedError(); 2495 } 2496 restrictionModeValue = static_cast<uint8_t>( 2497 securityNameSpace::RestrictionMode::convertModesFromString( 2498 std::get<std::string>(varRestrMode))); 2499 auto varSpecialMode = ctx->bus->yield_method_call<std::variant<uint8_t>>( 2500 *ctx->yield, ec, specialModeService, specialModeBasePath, 2501 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf, 2502 specialModeProperty); 2503 if (ec) 2504 { 2505 phosphor::logging::log<phosphor::logging::level::ERR>( 2506 "ipmiGetSecurityMode: failed to get SpecialMode property", 2507 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2508 // fall through, let us not worry about SpecialMode property, which is 2509 // not required in user scenario 2510 } 2511 else 2512 { 2513 specialModeValue = std::get<uint8_t>(varSpecialMode); 2514 } 2515 return ipmi::responseSuccess(restrictionModeValue, specialModeValue); 2516 } 2517 2518 /** @brief implements the set security mode command 2519 * Command allows to upgrade the restriction mode and won't allow 2520 * to downgrade from system interface 2521 * @param ctx - ctx pointer 2522 * @param restrictionMode - restriction mode value to be set. 2523 * 2524 * @returns IPMI completion code 2525 */ 2526 ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx, 2527 uint8_t restrictionMode) 2528 { 2529 namespace securityNameSpace = 2530 sdbusplus::xyz::openbmc_project::Control::Security::server; 2531 2532 ChannelInfo chInfo; 2533 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess) 2534 { 2535 phosphor::logging::log<phosphor::logging::level::ERR>( 2536 "ipmiSetSecurityMode: Failed to get Channel Info", 2537 phosphor::logging::entry("CHANNEL=%d", ctx->channel)); 2538 return ipmi::responseUnspecifiedError(); 2539 } 2540 auto reqMode = 2541 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode); 2542 2543 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) || 2544 (reqMode > 2545 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled)) 2546 { 2547 return ipmi::responseInvalidFieldRequest(); 2548 } 2549 2550 boost::system::error_code ec; 2551 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>( 2552 *ctx->yield, ec, restricionModeService, restricionModeBasePath, 2553 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf, 2554 restricionModeProperty); 2555 if (ec) 2556 { 2557 phosphor::logging::log<phosphor::logging::level::ERR>( 2558 "ipmiSetSecurityMode: failed to get RestrictionMode property", 2559 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2560 return ipmi::responseUnspecifiedError(); 2561 } 2562 auto currentRestrictionMode = 2563 securityNameSpace::RestrictionMode::convertModesFromString( 2564 std::get<std::string>(varRestrMode)); 2565 2566 if (chInfo.mediumType != 2567 static_cast<uint8_t>(EChannelMediumType::lan8032) && 2568 currentRestrictionMode > reqMode) 2569 { 2570 phosphor::logging::log<phosphor::logging::level::ERR>( 2571 "ipmiSetSecurityMode - Downgrading security mode not supported " 2572 "through system interface", 2573 phosphor::logging::entry( 2574 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)), 2575 phosphor::logging::entry("REQ_MODE=%d", restrictionMode)); 2576 return ipmi::responseCommandNotAvailable(); 2577 } 2578 2579 ec.clear(); 2580 ctx->bus->yield_method_call<>( 2581 *ctx->yield, ec, restricionModeService, restricionModeBasePath, 2582 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf, 2583 restricionModeProperty, 2584 static_cast<std::variant<std::string>>( 2585 securityNameSpace::convertForMessage(reqMode))); 2586 2587 if (ec) 2588 { 2589 phosphor::logging::log<phosphor::logging::level::ERR>( 2590 "ipmiSetSecurityMode: failed to set RestrictionMode property", 2591 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2592 return ipmi::responseUnspecifiedError(); 2593 } 2594 return ipmi::responseSuccess(); 2595 } 2596 2597 ipmi::RspType<uint8_t /* restore status */> 2598 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd) 2599 { 2600 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'}; 2601 2602 if (clr != expClr) 2603 { 2604 return ipmi::responseInvalidFieldRequest(); 2605 } 2606 constexpr uint8_t cmdStatus = 0; 2607 constexpr uint8_t cmdDefaultRestore = 0xaa; 2608 constexpr uint8_t cmdFullRestore = 0xbb; 2609 constexpr uint8_t cmdFormat = 0xcc; 2610 2611 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op"; 2612 2613 switch (cmd) 2614 { 2615 case cmdStatus: 2616 break; 2617 case cmdDefaultRestore: 2618 case cmdFullRestore: 2619 case cmdFormat: 2620 { 2621 // write file to rwfs root 2622 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3 2623 std::ofstream restoreFile(restoreOpFname); 2624 if (!restoreFile) 2625 { 2626 return ipmi::responseUnspecifiedError(); 2627 } 2628 restoreFile << value << "\n"; 2629 break; 2630 } 2631 default: 2632 return ipmi::responseInvalidFieldRequest(); 2633 } 2634 2635 constexpr uint8_t restorePending = 0; 2636 constexpr uint8_t restoreComplete = 1; 2637 2638 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname) 2639 ? restorePending 2640 : restoreComplete; 2641 return ipmi::responseSuccess(restoreStatus); 2642 } 2643 2644 ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void) 2645 { 2646 uint8_t bmcSource; 2647 namespace nmi = sdbusplus::com::intel::Control::server; 2648 2649 try 2650 { 2651 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2652 std::string service = 2653 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath); 2654 Value variant = 2655 getDbusProperty(*dbus, service, oemNmiSourceObjPath, 2656 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp); 2657 2658 switch (nmi::NMISource::convertBMCSourceSignalFromString( 2659 std::get<std::string>(variant))) 2660 { 2661 case nmi::NMISource::BMCSourceSignal::None: 2662 bmcSource = static_cast<uint8_t>(NmiSource::none); 2663 break; 2664 case nmi::NMISource::BMCSourceSignal::FpBtn: 2665 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn); 2666 break; 2667 case nmi::NMISource::BMCSourceSignal::WdPreTimeout: 2668 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout); 2669 break; 2670 case nmi::NMISource::BMCSourceSignal::PefMatch: 2671 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch); 2672 break; 2673 case nmi::NMISource::BMCSourceSignal::ChassisCmd: 2674 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd); 2675 break; 2676 case nmi::NMISource::BMCSourceSignal::MemoryError: 2677 bmcSource = static_cast<uint8_t>(NmiSource::memoryError); 2678 break; 2679 case nmi::NMISource::BMCSourceSignal::PciSerrPerr: 2680 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr); 2681 break; 2682 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi: 2683 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi); 2684 break; 2685 case nmi::NMISource::BMCSourceSignal::ChipsetNmi: 2686 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi); 2687 break; 2688 default: 2689 phosphor::logging::log<phosphor::logging::level::ERR>( 2690 "NMI source: invalid property!", 2691 phosphor::logging::entry( 2692 "PROP=%s", std::get<std::string>(variant).c_str())); 2693 return ipmi::responseResponseError(); 2694 } 2695 } 2696 catch (sdbusplus::exception::SdBusError& e) 2697 { 2698 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 2699 return ipmi::responseResponseError(); 2700 } 2701 2702 return ipmi::responseSuccess(bmcSource); 2703 } 2704 2705 ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId) 2706 { 2707 namespace nmi = sdbusplus::com::intel::Control::server; 2708 2709 nmi::NMISource::BMCSourceSignal bmcSourceSignal = 2710 nmi::NMISource::BMCSourceSignal::None; 2711 2712 switch (NmiSource(sourceId)) 2713 { 2714 case NmiSource::none: 2715 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None; 2716 break; 2717 case NmiSource::fpBtn: 2718 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn; 2719 break; 2720 case NmiSource::wdPreTimeout: 2721 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout; 2722 break; 2723 case NmiSource::pefMatch: 2724 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch; 2725 break; 2726 case NmiSource::chassisCmd: 2727 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd; 2728 break; 2729 case NmiSource::memoryError: 2730 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError; 2731 break; 2732 case NmiSource::pciSerrPerr: 2733 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr; 2734 break; 2735 case NmiSource::southbridgeNmi: 2736 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi; 2737 break; 2738 case NmiSource::chipsetNmi: 2739 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi; 2740 break; 2741 default: 2742 phosphor::logging::log<phosphor::logging::level::ERR>( 2743 "NMI source: invalid property!"); 2744 return ipmi::responseResponseError(); 2745 } 2746 2747 try 2748 { 2749 // keep NMI signal source 2750 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2751 std::string service = 2752 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath); 2753 setDbusProperty( 2754 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf, 2755 oemNmiBmcSourceObjPathProp, 2756 sdbusplus::com::intel::Control::server::convertForMessage( 2757 bmcSourceSignal)); 2758 // set Enabled property to inform NMI source handling 2759 // to trigger a NMI_OUT BSOD. 2760 // if it's triggered by NMI source property changed, 2761 // NMI_OUT BSOD could be missed if the same source occurs twice in a row 2762 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None) 2763 { 2764 setDbusProperty(*dbus, service, oemNmiSourceObjPath, 2765 oemNmiSourceIntf, oemNmiEnabledObjPathProp, 2766 static_cast<bool>(true)); 2767 } 2768 } 2769 catch (sdbusplus::exception_t& e) 2770 { 2771 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 2772 return ipmi::responseResponseError(); 2773 } 2774 2775 return ipmi::responseSuccess(); 2776 } 2777 2778 namespace dimmOffset 2779 { 2780 constexpr const char* dimmPower = "DimmPower"; 2781 constexpr const char* staticCltt = "StaticCltt"; 2782 constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm"; 2783 constexpr const char* offsetInterface = 2784 "xyz.openbmc_project.Inventory.Item.Dimm.Offset"; 2785 constexpr const char* property = "DimmOffset"; 2786 2787 }; // namespace dimmOffset 2788 2789 ipmi::RspType<> 2790 ipmiOEMSetDimmOffset(uint8_t type, 2791 const std::vector<std::tuple<uint8_t, uint8_t>>& data) 2792 { 2793 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) && 2794 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 2795 { 2796 return ipmi::responseInvalidFieldRequest(); 2797 } 2798 2799 if (data.empty()) 2800 { 2801 return ipmi::responseInvalidFieldRequest(); 2802 } 2803 nlohmann::json json; 2804 2805 std::ifstream jsonStream(dimmOffsetFile); 2806 if (jsonStream.good()) 2807 { 2808 json = nlohmann::json::parse(jsonStream, nullptr, false); 2809 if (json.is_discarded()) 2810 { 2811 json = nlohmann::json(); 2812 } 2813 jsonStream.close(); 2814 } 2815 2816 std::string typeName; 2817 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower)) 2818 { 2819 typeName = dimmOffset::dimmPower; 2820 } 2821 else 2822 { 2823 typeName = dimmOffset::staticCltt; 2824 } 2825 2826 nlohmann::json& field = json[typeName]; 2827 2828 for (const auto& [index, value] : data) 2829 { 2830 field[index] = value; 2831 } 2832 2833 for (nlohmann::json& val : field) 2834 { 2835 if (val == nullptr) 2836 { 2837 val = static_cast<uint8_t>(0); 2838 } 2839 } 2840 2841 std::ofstream output(dimmOffsetFile); 2842 if (!output.good()) 2843 { 2844 std::cerr << "Error writing json file\n"; 2845 return ipmi::responseResponseError(); 2846 } 2847 2848 output << json.dump(4); 2849 2850 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 2851 { 2852 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 2853 2854 std::variant<std::vector<uint8_t>> offsets = 2855 field.get<std::vector<uint8_t>>(); 2856 auto call = bus->new_method_call( 2857 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set"); 2858 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets); 2859 try 2860 { 2861 bus->call(call); 2862 } 2863 catch (sdbusplus::exception_t& e) 2864 { 2865 phosphor::logging::log<phosphor::logging::level::ERR>( 2866 "ipmiOEMSetDimmOffset: can't set dimm offsets!", 2867 phosphor::logging::entry("ERR=%s", e.what())); 2868 return ipmi::responseResponseError(); 2869 } 2870 } 2871 2872 return ipmi::responseSuccess(); 2873 } 2874 2875 ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index) 2876 { 2877 2878 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) && 2879 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 2880 { 2881 return ipmi::responseInvalidFieldRequest(); 2882 } 2883 2884 std::ifstream jsonStream(dimmOffsetFile); 2885 2886 auto json = nlohmann::json::parse(jsonStream, nullptr, false); 2887 if (json.is_discarded()) 2888 { 2889 std::cerr << "File error in " << dimmOffsetFile << "\n"; 2890 return ipmi::responseResponseError(); 2891 } 2892 2893 std::string typeName; 2894 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower)) 2895 { 2896 typeName = dimmOffset::dimmPower; 2897 } 2898 else 2899 { 2900 typeName = dimmOffset::staticCltt; 2901 } 2902 2903 auto it = json.find(typeName); 2904 if (it == json.end()) 2905 { 2906 return ipmi::responseInvalidFieldRequest(); 2907 } 2908 2909 if (it->size() <= index) 2910 { 2911 return ipmi::responseInvalidFieldRequest(); 2912 } 2913 2914 uint8_t resp = it->at(index).get<uint8_t>(); 2915 return ipmi::responseSuccess(resp); 2916 } 2917 2918 namespace boot_options 2919 { 2920 2921 using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server; 2922 using IpmiValue = uint8_t; 2923 constexpr auto ipmiDefault = 0; 2924 2925 std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = { 2926 {0x01, Source::Sources::Network}, 2927 {0x02, Source::Sources::Disk}, 2928 {0x05, Source::Sources::ExternalMedia}, 2929 {0x0f, Source::Sources::RemovableMedia}, 2930 {ipmiDefault, Source::Sources::Default}}; 2931 2932 std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = { 2933 {0x03, Mode::Modes::Safe}, 2934 {0x06, Mode::Modes::Setup}, 2935 {ipmiDefault, Mode::Modes::Regular}}; 2936 2937 std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = { 2938 {Source::Sources::Network, 0x01}, 2939 {Source::Sources::Disk, 0x02}, 2940 {Source::Sources::ExternalMedia, 0x05}, 2941 {Source::Sources::RemovableMedia, 0x0f}, 2942 {Source::Sources::Default, ipmiDefault}}; 2943 2944 std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = { 2945 {Mode::Modes::Safe, 0x03}, 2946 {Mode::Modes::Setup, 0x06}, 2947 {Mode::Modes::Regular, ipmiDefault}}; 2948 2949 static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; 2950 static constexpr auto bootSourceIntf = 2951 "xyz.openbmc_project.Control.Boot.Source"; 2952 static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable"; 2953 static constexpr auto persistentObjPath = 2954 "/xyz/openbmc_project/control/host0/boot"; 2955 static constexpr auto oneTimePath = 2956 "/xyz/openbmc_project/control/host0/boot/one_time"; 2957 static constexpr auto bootSourceProp = "BootSource"; 2958 static constexpr auto bootModeProp = "BootMode"; 2959 static constexpr auto oneTimeBootEnableProp = "Enabled"; 2960 static constexpr auto httpBootMode = 2961 "xyz.openbmc_project.Control.Boot.Source.Sources.Http"; 2962 2963 enum class BootOptionParameter : size_t 2964 { 2965 setInProgress = 0x0, 2966 bootFlags = 0x5, 2967 }; 2968 static constexpr uint8_t setComplete = 0x0; 2969 static constexpr uint8_t setInProgress = 0x1; 2970 static uint8_t transferStatus = setComplete; 2971 static constexpr uint8_t setParmVersion = 0x01; 2972 static constexpr uint8_t setParmBootFlagsPermanent = 0x40; 2973 static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80; 2974 static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0; 2975 static constexpr uint8_t httpBoot = 0xd; 2976 static constexpr uint8_t bootSourceMask = 0x3c; 2977 2978 } // namespace boot_options 2979 2980 ipmi::RspType<uint8_t, // version 2981 uint8_t, // param 2982 uint8_t, // data0, dependent on parameter 2983 std::optional<uint8_t> // data1, dependent on parameter 2984 > 2985 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block) 2986 { 2987 using namespace boot_options; 2988 uint8_t bootOption = 0; 2989 2990 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress)) 2991 { 2992 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus, 2993 std::nullopt); 2994 } 2995 2996 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags)) 2997 { 2998 phosphor::logging::log<phosphor::logging::level::ERR>( 2999 "Unsupported parameter"); 3000 return ipmi::responseResponseError(); 3001 } 3002 3003 try 3004 { 3005 auto oneTimeEnabled = false; 3006 // read one time Enabled property 3007 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 3008 std::string service = getService(*dbus, enabledIntf, oneTimePath); 3009 Value variant = getDbusProperty(*dbus, service, oneTimePath, 3010 enabledIntf, oneTimeBootEnableProp); 3011 oneTimeEnabled = std::get<bool>(variant); 3012 3013 // get BootSource and BootMode properties 3014 // according to oneTimeEnable 3015 auto bootObjPath = oneTimePath; 3016 if (oneTimeEnabled == false) 3017 { 3018 bootObjPath = persistentObjPath; 3019 } 3020 3021 service = getService(*dbus, bootModeIntf, bootObjPath); 3022 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf, 3023 bootModeProp); 3024 3025 auto bootMode = 3026 Mode::convertModesFromString(std::get<std::string>(variant)); 3027 3028 service = getService(*dbus, bootSourceIntf, bootObjPath); 3029 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf, 3030 bootSourceProp); 3031 3032 if (std::get<std::string>(variant) == httpBootMode) 3033 { 3034 bootOption = httpBoot; 3035 } 3036 else 3037 { 3038 auto bootSource = Source::convertSourcesFromString( 3039 std::get<std::string>(variant)); 3040 bootOption = sourceDbusToIpmi.at(bootSource); 3041 if (Source::Sources::Default == bootSource) 3042 { 3043 bootOption = modeDbusToIpmi.at(bootMode); 3044 } 3045 } 3046 3047 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime 3048 : setParmBootFlagsValidPermanent; 3049 bootOption <<= 2; // shift for responseconstexpr 3050 return ipmi::responseSuccess(setParmVersion, parameter, oneTime, 3051 bootOption); 3052 } 3053 catch (sdbusplus::exception_t& e) 3054 { 3055 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 3056 return ipmi::responseResponseError(); 3057 } 3058 } 3059 3060 ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam, 3061 std::optional<uint8_t> bootOption) 3062 { 3063 using namespace boot_options; 3064 auto oneTimeEnabled = false; 3065 3066 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress)) 3067 { 3068 if (bootOption) 3069 { 3070 return ipmi::responseReqDataLenInvalid(); 3071 } 3072 3073 if (transferStatus == setInProgress) 3074 { 3075 phosphor::logging::log<phosphor::logging::level::ERR>( 3076 "boot option set in progress!"); 3077 return ipmi::responseResponseError(); 3078 } 3079 3080 transferStatus = bootParam; 3081 return ipmi::responseSuccess(); 3082 } 3083 3084 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags) 3085 { 3086 phosphor::logging::log<phosphor::logging::level::ERR>( 3087 "Unsupported parameter"); 3088 return ipmi::responseResponseError(); 3089 } 3090 3091 if (!bootOption) 3092 { 3093 return ipmi::responseReqDataLenInvalid(); 3094 } 3095 3096 if (((bootOption.value() & bootSourceMask) >> 2) != 3097 httpBoot) // not http boot, exit 3098 { 3099 phosphor::logging::log<phosphor::logging::level::ERR>( 3100 "wrong boot option parameter!"); 3101 return ipmi::responseParmOutOfRange(); 3102 } 3103 3104 try 3105 { 3106 bool permanent = (bootParam & setParmBootFlagsPermanent) == 3107 setParmBootFlagsPermanent; 3108 3109 // read one time Enabled property 3110 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 3111 std::string service = getService(*dbus, enabledIntf, oneTimePath); 3112 Value variant = getDbusProperty(*dbus, service, oneTimePath, 3113 enabledIntf, oneTimeBootEnableProp); 3114 oneTimeEnabled = std::get<bool>(variant); 3115 3116 /* 3117 * Check if the current boot setting is onetime or permanent, if the 3118 * request in the command is otherwise, then set the "Enabled" 3119 * property in one_time object path to 'True' to indicate onetime 3120 * and 'False' to indicate permanent. 3121 * 3122 * Once the onetime/permanent setting is applied, then the bootMode 3123 * and bootSource is updated for the corresponding object. 3124 */ 3125 if (permanent == oneTimeEnabled) 3126 { 3127 setDbusProperty(*dbus, service, oneTimePath, enabledIntf, 3128 oneTimeBootEnableProp, !permanent); 3129 } 3130 3131 // set BootSource and BootMode properties 3132 // according to oneTimeEnable or persistent 3133 auto bootObjPath = oneTimePath; 3134 if (oneTimeEnabled == false) 3135 { 3136 bootObjPath = persistentObjPath; 3137 } 3138 std::string bootMode = 3139 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 3140 std::string bootSource = httpBootMode; 3141 3142 service = getService(*dbus, bootModeIntf, bootObjPath); 3143 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp, 3144 bootMode); 3145 3146 service = getService(*dbus, bootSourceIntf, bootObjPath); 3147 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf, 3148 bootSourceProp, bootSource); 3149 } 3150 catch (sdbusplus::exception_t& e) 3151 { 3152 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 3153 return ipmi::responseResponseError(); 3154 } 3155 3156 return ipmi::responseSuccess(); 3157 } 3158 3159 static void registerOEMFunctions(void) 3160 { 3161 phosphor::logging::log<phosphor::logging::level::INFO>( 3162 "Registering OEM commands"); 3163 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL, 3164 ipmiOEMWildcard, 3165 PRIVILEGE_USER); // wildcard default handler 3166 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL, 3167 ipmiOEMWildcard, 3168 PRIVILEGE_USER); // wildcard default handler 3169 ipmiPrintAndRegister( 3170 netfnIntcOEMGeneral, 3171 static_cast<ipmi_cmd_t>( 3172 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier), 3173 NULL, ipmiOEMGetChassisIdentifier, 3174 PRIVILEGE_USER); // get chassis identifier 3175 ipmiPrintAndRegister( 3176 netfnIntcOEMGeneral, 3177 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID), 3178 NULL, ipmiOEMSetSystemGUID, 3179 PRIVILEGE_ADMIN); // set system guid 3180 3181 // <Disable BMC System Reset Action> 3182 ipmi::registerHandler( 3183 ipmi::prioOemBase, netfnIntcOEMGeneral, 3184 static_cast<ipmi::Cmd>( 3185 IPMINetfnIntelOEMGeneralCmd::cmdDisableBMCSystemReset), 3186 ipmi::Privilege::Admin, ipmiOEMDisableBMCSystemReset); 3187 // <Get BMC Reset Disables> 3188 ipmi::registerHandler( 3189 ipmi::prioOemBase, netfnIntcOEMGeneral, 3190 static_cast<ipmi::Cmd>( 3191 IPMINetfnIntelOEMGeneralCmd::cmdGetBMCResetDisables), 3192 ipmi::Privilege::Admin, ipmiOEMGetBMCResetDisables); 3193 3194 ipmiPrintAndRegister( 3195 netfnIntcOEMGeneral, 3196 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID), 3197 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN); 3198 ipmiPrintAndRegister(netfnIntcOEMGeneral, 3199 static_cast<ipmi_cmd_t>( 3200 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo), 3201 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER); 3202 ipmiPrintAndRegister( 3203 netfnIntcOEMGeneral, 3204 static_cast<ipmi_cmd_t>( 3205 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords), 3206 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER); 3207 3208 ipmi::registerHandler( 3209 ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 3210 static_cast<ipmi::Cmd>( 3211 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus), 3212 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus); 3213 3214 ipmiPrintAndRegister( 3215 netfnIntcOEMGeneral, 3216 static_cast<ipmi_cmd_t>( 3217 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay), 3218 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR); 3219 ipmiPrintAndRegister( 3220 netfnIntcOEMGeneral, 3221 static_cast<ipmi_cmd_t>( 3222 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay), 3223 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER); 3224 3225 ipmi::registerHandler( 3226 ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 3227 static_cast<ipmi::Cmd>( 3228 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation), 3229 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation); 3230 3231 ipmi::registerHandler( 3232 ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 3233 static_cast<ipmi::Cmd>( 3234 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword), 3235 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword); 3236 3237 // <Get Processor Error Config> 3238 ipmi::registerHandler( 3239 ipmi::prioOemBase, netfnIntcOEMGeneral, 3240 static_cast<ipmi::Cmd>( 3241 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig), 3242 ipmi::Privilege::User, ipmiOEMGetProcessorErrConfig); 3243 // <Set Processor Error Config> 3244 ipmi::registerHandler( 3245 ipmi::prioOemBase, netfnIntcOEMGeneral, 3246 static_cast<ipmi::Cmd>( 3247 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig), 3248 ipmi::Privilege::Admin, ipmiOEMSetProcessorErrConfig); 3249 3250 ipmiPrintAndRegister(netfnIntcOEMGeneral, 3251 static_cast<ipmi_cmd_t>( 3252 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy), 3253 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN); 3254 ipmiPrintAndRegister(netfnIntcOEMGeneral, 3255 static_cast<ipmi_cmd_t>( 3256 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy), 3257 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN); 3258 3259 ipmiPrintAndRegister( 3260 netfnIntcOEMGeneral, 3261 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig), 3262 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER); 3263 3264 ipmi::registerHandler( 3265 ipmi::prioOemBase, netfnIntcOEMGeneral, 3266 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig), 3267 ipmi::Privilege::User, ipmiOEMGetFanConfig); 3268 3269 ipmi::registerHandler( 3270 ipmi::prioOemBase, netfnIntcOEMGeneral, 3271 static_cast<ipmi::Cmd>( 3272 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset), 3273 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset); 3274 3275 ipmi::registerHandler( 3276 ipmi::prioOemBase, netfnIntcOEMGeneral, 3277 static_cast<ipmi::Cmd>( 3278 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset), 3279 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset); 3280 3281 ipmi::registerHandler( 3282 ipmi::prioOemBase, netfnIntcOEMGeneral, 3283 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter), 3284 ipmi::Privilege::User, ipmiOEMSetFscParameter); 3285 3286 ipmi::registerHandler( 3287 ipmi::prioOemBase, netfnIntcOEMGeneral, 3288 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter), 3289 ipmi::Privilege::User, ipmiOEMGetFscParameter); 3290 3291 ipmi::registerHandler( 3292 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral, 3293 static_cast<ipmi::Cmd>( 3294 IPMINetfnIntelOEMGeneralCmd::cmdReadBaseBoardProductId), 3295 ipmi::Privilege::Admin, ipmiOEMReadBoardProductId); 3296 3297 ipmi::registerHandler( 3298 ipmi::prioOemBase, netfnIntcOEMGeneral, 3299 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetNmiStatus), 3300 ipmi::Privilege::User, ipmiOEMGetNmiSource); 3301 3302 ipmi::registerHandler( 3303 ipmi::prioOemBase, netfnIntcOEMGeneral, 3304 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetNmiStatus), 3305 ipmi::Privilege::Operator, ipmiOEMSetNmiSource); 3306 3307 ipmi::registerHandler( 3308 ipmi::prioOemBase, netfnIntcOEMGeneral, 3309 static_cast<ipmi::Cmd>( 3310 IPMINetfnIntelOEMGeneralCmd::cmdGetEfiBootOptions), 3311 ipmi::Privilege::User, ipmiOemGetEfiBootOptions); 3312 3313 ipmi::registerHandler( 3314 ipmi::prioOemBase, netfnIntcOEMGeneral, 3315 static_cast<ipmi::Cmd>( 3316 IPMINetfnIntelOEMGeneralCmd::cmdSetEfiBootOptions), 3317 ipmi::Privilege::Operator, ipmiOemSetEfiBootOptions); 3318 3319 ipmi::registerHandler( 3320 ipmi::prioOemBase, netfnIntcOEMGeneral, 3321 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetSecurityMode), 3322 Privilege::User, ipmiGetSecurityMode); 3323 3324 ipmi::registerHandler( 3325 ipmi::prioOemBase, netfnIntcOEMGeneral, 3326 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetSecurityMode), 3327 Privilege::Admin, ipmiSetSecurityMode); 3328 3329 ipmiPrintAndRegister( 3330 netfnIntcOEMGeneral, 3331 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus), 3332 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN); 3333 ipmiPrintAndRegister( 3334 netfnIntcOEMPlatform, 3335 static_cast<ipmi_cmd_t>( 3336 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed), 3337 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN); 3338 ipmi::registerHandler( 3339 ipmi::prioOemBase, netfnIntcOEMGeneral, 3340 static_cast<ipmi::Cmd>( 3341 IPMINetfnIntelOEMGeneralCmd::cmdSetFaultIndication), 3342 ipmi::Privilege::Operator, ipmiOEMSetFaultIndication); 3343 3344 ipmi::registerHandler( 3345 ipmi::prioOemBase, netfnIntcOEMGeneral, 3346 static_cast<ipmi::Cmd>( 3347 IPMINetfnIntelOEMGeneralCmd::cmdSetColdRedundancyConfig), 3348 ipmi::Privilege::User, ipmiOEMSetCRConfig); 3349 ipmi::registerHandler( 3350 ipmi::prioOemBase, netfnIntcOEMGeneral, 3351 static_cast<ipmi::Cmd>( 3352 IPMINetfnIntelOEMGeneralCmd::cmdGetColdRedundancyConfig), 3353 ipmi::Privilege::User, ipmiOEMGetCRConfig); 3354 3355 registerHandler(prioOemBase, netfn::intel::oemGeneral, 3356 netfn::intel::cmdRestoreConfiguration, Privilege::Admin, 3357 ipmiRestoreConfiguration); 3358 3359 ipmi::registerHandler( 3360 ipmi::prioOemBase, netfnIntcOEMGeneral, 3361 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetDimmOffset), 3362 ipmi::Privilege::Operator, ipmiOEMSetDimmOffset); 3363 3364 ipmi::registerHandler( 3365 ipmi::prioOemBase, netfnIntcOEMGeneral, 3366 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetDimmOffset), 3367 ipmi::Privilege::Operator, ipmiOEMGetDimmOffset); 3368 } 3369 3370 } // namespace ipmi 3371