blob: 33425697a87d5c602632c3c38a5b92b874396ba6 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM 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 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016#include "config.h"
17
Matt Spinlerc8705e22019-09-11 12:36:07 -050018#include "data_interface.hpp"
19
Matt Spinlercad9c2b2019-12-02 15:42:01 -060020#include <fstream>
Matt Spinlera7d9d962019-11-06 15:01:25 -060021#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
22
Matt Spinlerc8705e22019-09-11 12:36:07 -050023namespace openpower
24{
25namespace pels
26{
27
28namespace service_name
29{
30constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
31} // namespace service_name
32
33namespace object_path
34{
35constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
36constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinlera7d9d962019-11-06 15:01:25 -060037constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060038constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinlerc8705e22019-09-11 12:36:07 -050039} // namespace object_path
40
41namespace interface
42{
43constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
44constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
45constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlera7d9d962019-11-06 15:01:25 -060046constexpr auto osStatus = "xyz.openbmc_project.State.OperatingSystem.Status";
Matt Spinlerb3f51862019-12-09 13:55:10 -060047constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinlerc8705e22019-09-11 12:36:07 -050048} // namespace interface
49
Matt Spinlera7d9d962019-11-06 15:01:25 -060050using namespace sdbusplus::xyz::openbmc_project::State::OperatingSystem::server;
51
Matt Spinlerc8705e22019-09-11 12:36:07 -050052DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus)
53{
54 readMTMS();
Matt Spinlera7d9d962019-11-06 15:01:25 -060055 readHostState();
Matt Spinlercad9c2b2019-12-02 15:42:01 -060056 readBMCFWVersion();
57 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -060058 readBMCFWVersionID();
Matt Spinlerc8705e22019-09-11 12:36:07 -050059}
60
61void DataInterface::readMTMS()
62{
63 // If this runs when the inventory service isn't running, it will get the
64 // value whenever it starts via the propertiesChanged callback.
65 try
66 {
67 auto inventoryService =
68 getService(object_path::systemInv, interface::invAsset);
69
70 if (!inventoryService.empty())
71 {
72 auto properties = getAllProperties(
73 inventoryService, object_path::systemInv, interface::invAsset);
74
75 _machineTypeModel = std::get<std::string>(properties["Model"]);
76
77 _machineSerialNumber =
78 std::get<std::string>(properties["SerialNumber"]);
79 }
80 }
81 catch (std::exception& e)
82 {
83 // Inventory must not be running at this moment.
84 }
85
86 // Keep up to date by watching for the propertiesChanged signal.
87 _sysInventoryPropMatch = std::make_unique<sdbusplus::bus::match_t>(
88 _bus,
89 sdbusplus::bus::match::rules::propertiesChanged(object_path::systemInv,
90 interface::invAsset),
91 std::bind(std::mem_fn(&DataInterface::sysAssetPropChanged), this,
92 std::placeholders::_1));
93}
94
95void DataInterface::sysAssetPropChanged(sdbusplus::message::message& msg)
96{
97 DBusInterface interface;
98 DBusPropertyMap properties;
99
100 msg.read(interface, properties);
101
102 auto model = properties.find("Model");
103 if (model != properties.end())
104 {
105 _machineTypeModel = std::get<std::string>(model->second);
106 }
107
108 auto sn = properties.find("SerialNumber");
109 if (sn != properties.end())
110 {
111 _machineSerialNumber = std::get<std::string>(sn->second);
112 }
113}
114
115DBusPropertyMap DataInterface::getAllProperties(const std::string& service,
116 const std::string& objectPath,
117 const std::string& interface)
118{
119 DBusPropertyMap properties;
120
121 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
122 interface::dbusProperty, "GetAll");
123 method.append(interface);
124 auto reply = _bus.call(method);
125
126 reply.read(properties);
127
128 return properties;
129}
130
Matt Spinlera7d9d962019-11-06 15:01:25 -0600131void DataInterface::getProperty(const std::string& service,
132 const std::string& objectPath,
133 const std::string& interface,
134 const std::string& property, DBusValue& value)
135{
136
137 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
138 interface::dbusProperty, "Get");
139 method.append(interface, property);
140 auto reply = _bus.call(method);
141
142 reply.read(value);
143}
144
Matt Spinlerc8705e22019-09-11 12:36:07 -0500145DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600146 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500147{
148 auto method = _bus.new_method_call(service_name::objectMapper,
149 object_path::objectMapper,
150 interface::objectMapper, "GetObject");
151
152 method.append(objectPath, std::vector<std::string>({interface}));
153
154 auto reply = _bus.call(method);
155
156 std::map<DBusService, DBusInterfaceList> response;
157 reply.read(response);
158
159 if (!response.empty())
160 {
161 return response.begin()->first;
162 }
163
164 return std::string{};
165}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600166
167void DataInterface::readHostState()
168{
169 _hostUp = false;
170
171 try
172 {
173 auto service = getService(object_path::hostState, interface::osStatus);
174 if (!service.empty())
175 {
176 DBusValue value;
177 getProperty(service, object_path::hostState, interface::osStatus,
178 "OperatingSystemState", value);
179
180 auto status =
181 Status::convertOSStatusFromString(std::get<std::string>(value));
182
183 if ((status == Status::OSStatus::BootComplete) ||
184 (status == Status::OSStatus::Standby))
185 {
186 _hostUp = true;
187 }
188 }
189 }
190 catch (std::exception& e)
191 {
192 // Not available yet.
193 }
194
195 // Keep up to date by watching for the propertiesChanged signal.
196 _osStateMatch = std::make_unique<sdbusplus::bus::match_t>(
197 _bus,
198 sdbusplus::bus::match::rules::propertiesChanged(object_path::hostState,
199 interface::osStatus),
200 std::bind(std::mem_fn(&DataInterface::osStatePropChanged), this,
201 std::placeholders::_1));
202}
203
204void DataInterface::osStatePropChanged(sdbusplus::message::message& msg)
205{
206 DBusInterface interface;
207 DBusPropertyMap properties;
208
209 msg.read(interface, properties);
210
211 auto state = properties.find("OperatingSystemState");
212 if (state != properties.end())
213 {
214 auto status = Status::convertOSStatusFromString(
215 std::get<std::string>(state->second));
216
217 bool newHostState = false;
218 if ((status == Status::OSStatus::BootComplete) ||
219 (status == Status::OSStatus::Standby))
220 {
221 newHostState = true;
222 }
223
224 setHostState(newHostState);
225 }
226}
227
Matt Spinlerb3f51862019-12-09 13:55:10 -0600228uint8_t DataInterface::getPLDMInstanceID(uint8_t eid) const
229{
230 return 0;
231// Don't use until PLDM switches to async D-Bus.
232#if 0
233 auto service = getService(object_path::pldm, interface::pldmRequester);
234
235 auto method =
236 _bus.new_method_call(service.c_str(), object_path::pldm,
237 interface::pldmRequester, "GetInstanceId");
238 method.append(eid);
239 auto reply = _bus.call(method);
240
241 uint8_t instanceID = 0;
242 reply.read(instanceID);
243
244 return instanceID;
245#endif
246}
247
Matt Spinler677381b2020-01-23 10:04:29 -0600248/**
249 * @brief Return a value found in the /etc/os-release file
250 *
251 * @param[in] key - The key name, like "VERSION"
252 *
253 * @return std::optional<std::string> - The value
254 */
255std::optional<std::string> getOSReleaseValue(const std::string& key)
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600256{
257 std::ifstream versionFile{BMC_VERSION_FILE};
258 std::string line;
Matt Spinler677381b2020-01-23 10:04:29 -0600259 std::string keyPattern{key + '='};
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600260
261 while (std::getline(versionFile, line))
262 {
Matt Spinler677381b2020-01-23 10:04:29 -0600263 if (line.find(keyPattern) != std::string::npos)
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600264 {
265 auto pos = line.find_first_of('"') + 1;
Matt Spinler677381b2020-01-23 10:04:29 -0600266 auto value = line.substr(pos, line.find_last_of('"') - pos);
267 return value;
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600268 }
269 }
Matt Spinler677381b2020-01-23 10:04:29 -0600270
271 return std::nullopt;
272}
273
274void DataInterface::readBMCFWVersion()
275{
276 _bmcFWVersion = getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600277}
278
279void DataInterface::readServerFWVersion()
280{
281 // Not available yet
282}
283
Matt Spinler677381b2020-01-23 10:04:29 -0600284void DataInterface::readBMCFWVersionID()
285{
286 _bmcFWVersionID = getOSReleaseValue("VERSION_ID").value_or("");
287}
288
Matt Spinlerc8705e22019-09-11 12:36:07 -0500289} // namespace pels
290} // namespace openpower