diff options
Diffstat (limited to 'extensions/openpower-pels/data_interface.cpp')
-rw-r--r-- | extensions/openpower-pels/data_interface.cpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/extensions/openpower-pels/data_interface.cpp b/extensions/openpower-pels/data_interface.cpp new file mode 100644 index 0000000..3342569 --- /dev/null +++ b/extensions/openpower-pels/data_interface.cpp @@ -0,0 +1,290 @@ +/** + * Copyright © 2019 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "config.h" + +#include "data_interface.hpp" + +#include <fstream> +#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp> + +namespace openpower +{ +namespace pels +{ + +namespace service_name +{ +constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper"; +} // namespace service_name + +namespace object_path +{ +constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper"; +constexpr auto systemInv = "/xyz/openbmc_project/inventory/system"; +constexpr auto hostState = "/xyz/openbmc_project/state/host0"; +constexpr auto pldm = "/xyz/openbmc_project/pldm"; +} // namespace object_path + +namespace interface +{ +constexpr auto dbusProperty = "org.freedesktop.DBus.Properties"; +constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper"; +constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset"; +constexpr auto osStatus = "xyz.openbmc_project.State.OperatingSystem.Status"; +constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester"; +} // namespace interface + +using namespace sdbusplus::xyz::openbmc_project::State::OperatingSystem::server; + +DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus) +{ + readMTMS(); + readHostState(); + readBMCFWVersion(); + readServerFWVersion(); + readBMCFWVersionID(); +} + +void DataInterface::readMTMS() +{ + // If this runs when the inventory service isn't running, it will get the + // value whenever it starts via the propertiesChanged callback. + try + { + auto inventoryService = + getService(object_path::systemInv, interface::invAsset); + + if (!inventoryService.empty()) + { + auto properties = getAllProperties( + inventoryService, object_path::systemInv, interface::invAsset); + + _machineTypeModel = std::get<std::string>(properties["Model"]); + + _machineSerialNumber = + std::get<std::string>(properties["SerialNumber"]); + } + } + catch (std::exception& e) + { + // Inventory must not be running at this moment. + } + + // Keep up to date by watching for the propertiesChanged signal. + _sysInventoryPropMatch = std::make_unique<sdbusplus::bus::match_t>( + _bus, + sdbusplus::bus::match::rules::propertiesChanged(object_path::systemInv, + interface::invAsset), + std::bind(std::mem_fn(&DataInterface::sysAssetPropChanged), this, + std::placeholders::_1)); +} + +void DataInterface::sysAssetPropChanged(sdbusplus::message::message& msg) +{ + DBusInterface interface; + DBusPropertyMap properties; + + msg.read(interface, properties); + + auto model = properties.find("Model"); + if (model != properties.end()) + { + _machineTypeModel = std::get<std::string>(model->second); + } + + auto sn = properties.find("SerialNumber"); + if (sn != properties.end()) + { + _machineSerialNumber = std::get<std::string>(sn->second); + } +} + +DBusPropertyMap DataInterface::getAllProperties(const std::string& service, + const std::string& objectPath, + const std::string& interface) +{ + DBusPropertyMap properties; + + auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), + interface::dbusProperty, "GetAll"); + method.append(interface); + auto reply = _bus.call(method); + + reply.read(properties); + + return properties; +} + +void DataInterface::getProperty(const std::string& service, + const std::string& objectPath, + const std::string& interface, + const std::string& property, DBusValue& value) +{ + + auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), + interface::dbusProperty, "Get"); + method.append(interface, property); + auto reply = _bus.call(method); + + reply.read(value); +} + +DBusService DataInterface::getService(const std::string& objectPath, + const std::string& interface) const +{ + auto method = _bus.new_method_call(service_name::objectMapper, + object_path::objectMapper, + interface::objectMapper, "GetObject"); + + method.append(objectPath, std::vector<std::string>({interface})); + + auto reply = _bus.call(method); + + std::map<DBusService, DBusInterfaceList> response; + reply.read(response); + + if (!response.empty()) + { + return response.begin()->first; + } + + return std::string{}; +} + +void DataInterface::readHostState() +{ + _hostUp = false; + + try + { + auto service = getService(object_path::hostState, interface::osStatus); + if (!service.empty()) + { + DBusValue value; + getProperty(service, object_path::hostState, interface::osStatus, + "OperatingSystemState", value); + + auto status = + Status::convertOSStatusFromString(std::get<std::string>(value)); + + if ((status == Status::OSStatus::BootComplete) || + (status == Status::OSStatus::Standby)) + { + _hostUp = true; + } + } + } + catch (std::exception& e) + { + // Not available yet. + } + + // Keep up to date by watching for the propertiesChanged signal. + _osStateMatch = std::make_unique<sdbusplus::bus::match_t>( + _bus, + sdbusplus::bus::match::rules::propertiesChanged(object_path::hostState, + interface::osStatus), + std::bind(std::mem_fn(&DataInterface::osStatePropChanged), this, + std::placeholders::_1)); +} + +void DataInterface::osStatePropChanged(sdbusplus::message::message& msg) +{ + DBusInterface interface; + DBusPropertyMap properties; + + msg.read(interface, properties); + + auto state = properties.find("OperatingSystemState"); + if (state != properties.end()) + { + auto status = Status::convertOSStatusFromString( + std::get<std::string>(state->second)); + + bool newHostState = false; + if ((status == Status::OSStatus::BootComplete) || + (status == Status::OSStatus::Standby)) + { + newHostState = true; + } + + setHostState(newHostState); + } +} + +uint8_t DataInterface::getPLDMInstanceID(uint8_t eid) const +{ + return 0; +// Don't use until PLDM switches to async D-Bus. +#if 0 + auto service = getService(object_path::pldm, interface::pldmRequester); + + auto method = + _bus.new_method_call(service.c_str(), object_path::pldm, + interface::pldmRequester, "GetInstanceId"); + method.append(eid); + auto reply = _bus.call(method); + + uint8_t instanceID = 0; + reply.read(instanceID); + + return instanceID; +#endif +} + +/** + * @brief Return a value found in the /etc/os-release file + * + * @param[in] key - The key name, like "VERSION" + * + * @return std::optional<std::string> - The value + */ +std::optional<std::string> getOSReleaseValue(const std::string& key) +{ + std::ifstream versionFile{BMC_VERSION_FILE}; + std::string line; + std::string keyPattern{key + '='}; + + while (std::getline(versionFile, line)) + { + if (line.find(keyPattern) != std::string::npos) + { + auto pos = line.find_first_of('"') + 1; + auto value = line.substr(pos, line.find_last_of('"') - pos); + return value; + } + } + + return std::nullopt; +} + +void DataInterface::readBMCFWVersion() +{ + _bmcFWVersion = getOSReleaseValue("VERSION").value_or(""); +} + +void DataInterface::readServerFWVersion() +{ + // Not available yet +} + +void DataInterface::readBMCFWVersionID() +{ + _bmcFWVersionID = getOSReleaseValue("VERSION_ID").value_or(""); +} + +} // namespace pels +} // namespace openpower |