#include "dcmihandler.hpp" #include "host-ipmid/ipmid-api.h" #include #include #include #include #include "utils.hpp" #include "xyz/openbmc_project/Common/error.hpp" using namespace phosphor::logging; using InternalFailure = sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; void register_netfn_dcmi_functions() __attribute__((constructor)); ipmi_ret_t ipmi_dcmi_get_power_limit(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request, ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context) { ipmi_ret_t rc = IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT; // dcmi-v1-5-rev-spec.pdf 6.6.2. // This is good enough for OpenBMC support for OpenPOWER based systems // TODO research if more is needed uint8_t data_response[] = { 0xDC, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; printf("IPMI DCMI_GET_POWER_LEVEL\n"); memcpy(response, data_response, sizeof(data_response)); *data_len = sizeof(data_response); return rc; } namespace dcmi { void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree) { static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper"; static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper"; static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper"; static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/"; sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; auto depth = 0; auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath, mapperIface, "GetSubTree"); mapperCall.append(inventoryRoot); mapperCall.append(depth); mapperCall.append(std::vector({dcmi::assetTagIntf})); auto mapperReply = bus.call(mapperCall); if (mapperReply.is_method_error()) { log("Error in mapper call"); elog(); } mapperReply.read(objectTree); if (objectTree.empty()) { log("AssetTag property is not populated"); elog(); } } std::string readAssetTag() { sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; dcmi::assettag::ObjectTree objectTree; // Read the object tree with the inventory root to figure out the object // that has implemented the Asset tag interface. readAssetTagObjectTree(objectTree); auto method = bus.new_method_call( (objectTree.begin()->second.begin()->first).c_str(), (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get"); method.append(dcmi::assetTagIntf); method.append(dcmi::assetTagProp); auto reply = bus.call(method); if (reply.is_method_error()) { log("Error in reading asset tag"); elog(); } sdbusplus::message::variant assetTag; reply.read(assetTag); return assetTag.get(); } } // namespace dcmi ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request, ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context) { auto requestData = reinterpret_cast (request); std::vector outPayload(sizeof(dcmi::GetAssetTagResponse)); auto responseData = reinterpret_cast (outPayload.data()); if (requestData->groupID != dcmi::groupExtId) { *data_len = 0; return IPMI_CC_INVALID_FIELD_REQUEST; } // Verify offset to read and number of bytes to read are not exceeding the // range. if ((requestData->offset > dcmi::assetTagMaxOffset) || (requestData->bytes > dcmi::maxBytes) || ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize)) { *data_len = 0; return IPMI_CC_PARM_OUT_OF_RANGE; } std::string assetTag; try { assetTag = dcmi::readAssetTag(); } catch (InternalFailure& e) { *data_len = 0; return IPMI_CC_UNSPECIFIED_ERROR; } responseData->groupID = dcmi::groupExtId; // Return if the asset tag is not populated. if (!assetTag.size()) { responseData->tagLength = 0; memcpy(response, outPayload.data(), outPayload.size()); *data_len = outPayload.size(); return IPMI_CC_OK; } // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit // Get Asset Tag command. if (assetTag.size() > dcmi::assetTagMaxSize) { assetTag.resize(dcmi::assetTagMaxSize); } // If the requested offset is beyond the asset tag size. if (requestData->offset >= assetTag.size()) { *data_len = 0; return IPMI_CC_PARM_OUT_OF_RANGE; } auto returnData = assetTag.substr(requestData->offset, requestData->bytes); responseData->tagLength = assetTag.size(); memcpy(response, outPayload.data(), outPayload.size()); memcpy(static_cast(response) + outPayload.size(), returnData.data(), returnData.size()); *data_len = outPayload.size() + returnData.size(); return IPMI_CC_OK; } void register_netfn_dcmi_functions() { // printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER); ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER, NULL, ipmi_dcmi_get_power_limit, PRIVILEGE_USER); // printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG); ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG, NULL, getAssetTag, PRIVILEGE_USER); return; } // 956379