blob: 585a07d5fbf926be9aff72432694a360196d841f [file] [log] [blame]
Caleb Palmer626270a2022-02-21 11:05:08 -06001#include <fmt/format.h>
2
Ben Tyner324234b2021-06-28 17:01:17 -05003#include <util/dbus.hpp>
4#include <util/trace.hpp>
Ben Tynerfe2c50d2021-07-23 13:38:53 -05005#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Ben Tyner324234b2021-06-28 17:01:17 -05006
7namespace util
8{
9
10namespace dbus
11{
12
13//------------------------------------------------------------------------------
14
15constexpr auto objectMapperService = "xyz.openbmc_project.ObjectMapper";
16constexpr auto objectMapperPath = "/xyz/openbmc_project/object_mapper";
17constexpr auto objectMapperInterface = "xyz.openbmc_project.ObjectMapper";
18
19/** @brief Find the path and service that implements the given interface */
20int find(const std::string& i_interface, std::string& o_path,
21 std::string& o_service)
22{
23 int rc = 1; // assume not success
24
25 auto bus = sdbusplus::bus::new_default();
26
Ben Tyner324234b2021-06-28 17:01:17 -050027 try
28 {
Ben Tyner659e65c2021-07-21 09:49:35 -050029 constexpr auto function = "GetSubTree";
30
Ben Tyner324234b2021-06-28 17:01:17 -050031 auto method = bus.new_method_call(objectMapperService, objectMapperPath,
32 objectMapperInterface, function);
33
34 // Search the entire dbus tree for the specified interface
35 method.append(std::string{"/"}, 0,
36 std::vector<std::string>{i_interface});
37
38 auto reply = bus.call(method);
39
40 DBusSubTree response;
41 reply.read(response);
42
43 if (!response.empty())
44 {
45 // Response is a map of object paths to a map of service, interfaces
46 auto object = *(response.begin());
47 o_path = object.first; // return path
48 o_service = object.second.begin()->first; // return service
49
50 rc = 0; // success
51 }
52 }
53 catch (const sdbusplus::exception::SdBusError& e)
54 {
55 trace::err("util::dbus::find exception");
56 std::string traceMsg = std::string(e.what());
57 trace::err(traceMsg.c_str());
58 }
59
60 return rc;
61}
62
63/** @brief Find the service that implements the given object and interface */
64int findService(const std::string& i_interface, const std::string& i_path,
65 std::string& o_service)
66{
67 int rc = 1; // assume not success
68
69 auto bus = sdbusplus::bus::new_default();
70
Ben Tyner324234b2021-06-28 17:01:17 -050071 try
72 {
Ben Tyner659e65c2021-07-21 09:49:35 -050073 constexpr auto function = "GetObject";
74
Ben Tyner324234b2021-06-28 17:01:17 -050075 auto method = bus.new_method_call(objectMapperService, objectMapperPath,
76 objectMapperInterface, function);
77
78 // Find services that implement the object path, constrain the search
79 // to the given interface.
80 method.append(i_path, std::vector<std::string>{i_interface});
81
82 auto reply = bus.call(method);
83
84 // response is a map of service names to their interfaces
85 std::map<DBusService, DBusInterfaceList> response;
86 reply.read(response);
87
88 if (!response.empty())
89 {
90 // return the service
91 o_service = response.begin()->first;
92
93 rc = 0; // success
94 }
95 }
96 catch (const sdbusplus::exception::SdBusError& e)
97 {
98 trace::err("util::dbus::map exception");
99 std::string traceMsg = std::string(e.what());
100 trace::err(traceMsg.c_str());
101 }
102
103 return rc;
104}
105
106/** @brief Read a property from a dbus object interface */
107int getProperty(const std::string& i_interface, const std::string& i_path,
108 const std::string& i_service, const std::string& i_property,
109 DBusValue& o_response)
110{
111 int rc = 1; // assume not success
112
113 auto bus = sdbusplus::bus::new_default();
114
Ben Tyner324234b2021-06-28 17:01:17 -0500115 try
116 {
Ben Tyner659e65c2021-07-21 09:49:35 -0500117 constexpr auto interface = "org.freedesktop.DBus.Properties";
118 constexpr auto function = "Get";
119
Ben Tyner324234b2021-06-28 17:01:17 -0500120 // calling the get property method
121 auto method = bus.new_method_call(i_service.c_str(), i_path.c_str(),
122 interface, function);
123
124 method.append(i_interface, i_property);
125 auto reply = bus.call(method);
126
127 // returning the property value
128 reply.read(o_response);
129
130 rc = 0; // success
131 }
132 catch (const sdbusplus::exception::SdBusError& e)
133 {
134 trace::err("util::dbus::getProperty exception");
135 std::string traceMsg = std::string(e.what());
136 trace::err(traceMsg.c_str());
137 }
138
139 return rc;
140}
141
142/** @brief Get the IBM compatible names defined for this system */
143std::vector<std::string> systemNames()
144{
145 std::vector<std::string> names;
146
147 constexpr auto interface =
148 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
149
150 DBusService service;
151 DBusPath path;
152
153 // find a dbus object and path that implements the interface
154 if (0 == find(interface, path, service))
155 {
156 DBusValue value;
157
158 // compatible system names are implemented as a property
159 constexpr auto property = "Names";
160
161 if (0 == getProperty(interface, path, service, property, value))
162 {
163 // return value is a variant, names are in the vector
164 names = std::get<std::vector<std::string>>(value);
165 }
166 }
167
168 return names;
169}
170
Ben Tyner93067162021-07-23 10:39:30 -0500171/** @brief Transition the host state */
172void transitionHost(const HostState i_hostState)
173{
174 try
175 {
176 // We will be transitioning host by starting appropriate dbus target
177 std::string target = "obmc-host-quiesce@0.target"; // quiesce is default
178
179 // crash (mpipl) mode state requested
180 if (HostState::Crash == i_hostState)
181 {
182 target = "obmc-host-crash@0.target";
183 }
184
185 auto bus = sdbusplus::bus::new_system();
186 auto method = bus.new_method_call(
187 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
188 "org.freedesktop.systemd1.Manager", "StartUnit");
189
190 method.append(target); // target unit to start
191 method.append("replace"); // mode = replace conflicting queued jobs
192
193 bus.call_noreply(method); // start the service
194 }
195 catch (const sdbusplus::exception::SdBusError& e)
196 {
197 trace::err("util::dbus::transitionHost exception");
198 std::string traceMsg = std::string(e.what());
199 trace::err(traceMsg.c_str());
200 }
201}
202
Ben Tyner39fcf652021-10-19 20:38:29 -0500203/** @brief Read state of autoRebootEnabled property via dbus */
Ben Tynerffb48672021-07-23 12:29:03 -0500204bool autoRebootEnabled()
205{
Ben Tyner39fcf652021-10-19 20:38:29 -0500206 // Assume true in case autoRebootEnbabled property is not available
207 bool autoReboot = true;
Ben Tynerffb48672021-07-23 12:29:03 -0500208
209 constexpr auto interface = "xyz.openbmc_project.Control.Boot.RebootPolicy";
210
Ben Tyner39fcf652021-10-19 20:38:29 -0500211 DBusService service; // will find this
212 DBusPath path; // will find this
Ben Tynerffb48672021-07-23 12:29:03 -0500213
214 // find a dbus object and path that implements the interface
215 if (0 == find(interface, path, service))
216 {
217 DBusValue value;
218
219 // autoreboot policy is implemented as a property
220 constexpr auto property = "AutoReboot";
221
222 if (0 == getProperty(interface, path, service, property, value))
223 {
224 // return value is a variant, autoreboot policy is boolean
225 autoReboot = std::get<bool>(value);
226 }
227 }
228
229 return autoReboot;
230}
231
Ben Tynerfe2c50d2021-07-23 13:38:53 -0500232/** @brief Get the running state of the host */
233HostRunningState hostRunningState()
234{
235 // assume not able to get host running state
236 HostRunningState host = HostRunningState::Unknown;
237
238 constexpr auto interface = "xyz.openbmc_project.State.Boot.Progress";
239
240 DBusService service;
241 DBusPath path;
242
243 // find a dbus object and path that implements the interface
244 if (0 == find(interface, path, service))
245 {
246 DBusValue value;
247
248 // boot progress is implemented as a property
249 constexpr auto property = "BootProgress";
250
251 if (0 == getProperty(interface, path, service, property, value))
252 {
253 // return value is a variant, progress is in the vector of strings
254 std::string bootProgress(std::get<std::string>(value));
255
256 // convert boot progress to host state
257 using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::
258 server::Progress::ProgressStages;
259
260 BootProgress stage = sdbusplus::xyz::openbmc_project::State::Boot::
261 server::Progress::convertProgressStagesFromString(bootProgress);
262
263 if ((stage == BootProgress::SystemInitComplete) ||
264 (stage == BootProgress::OSStart) ||
265 (stage == BootProgress::OSRunning))
266 {
267 host = HostRunningState::Started;
268 }
269 else
270 {
271 host = HostRunningState::NotStarted;
272 }
273 }
274 }
275
276 return host;
277}
278
Ben Tyner39fcf652021-10-19 20:38:29 -0500279/** @brief Read state of dumpPolicyEnabled property via dbus */
280bool dumpPolicyEnabled()
281{
282 // Assume true In case dumpPolicyEnabled property is not available
283 bool dumpPolicyEnabled = true;
284
285 constexpr auto interface = "xyz.openbmc_project.Object.Enable";
286 constexpr auto path = "/xyz/openbmc_project/dump/system_dump_policy";
287
288 DBusService service; // will find this
289
290 // find a dbus object and path that implements the interface
291 if (0 == findService(interface, path, service))
292 {
293 DBusValue value;
294
295 // autoreboot policy is implemented as a property
296 constexpr auto property = "Enabled";
297
298 if (0 == getProperty(interface, path, service, property, value))
299 {
300 // return value is a variant, dump policy enabled is a boolean
301 dumpPolicyEnabled = std::get<bool>(value);
302 }
303 }
304
305 return dumpPolicyEnabled;
306}
307
Ben Tyner13159682022-02-16 14:55:38 -0600308/** @brief Create a PEL */
309uint32_t createPel(const std::string& i_message, const std::string& i_severity,
310 std::map<std::string, std::string>& io_additional,
311 const std::vector<util::FFDCTuple>& i_ffdc)
312{
313 // CreatePELWithFFDCFiles returns plid
314 int plid = 0;
315
316 // Sdbus call specifics
317 constexpr auto interface = "org.open_power.Logging.PEL";
318 constexpr auto path = "/xyz/openbmc_project/logging";
319
320 // we need to find the service implementing the interface
321 util::dbus::DBusService service;
322
323 if (0 == findService(interface, path, service))
324 {
325 try
326 {
327 constexpr auto function = "CreatePELWithFFDCFiles";
328
329 // The "Create" method requires manually adding the process ID.
330 io_additional["_PID"] = std::to_string(getpid());
331
332 // create dbus method
333 auto bus = sdbusplus::bus::new_system();
Patrick Williamse212fb02022-07-22 19:26:57 -0500334 sdbusplus::message_t method =
Ben Tyner13159682022-02-16 14:55:38 -0600335 bus.new_method_call(service.c_str(), path, interface, function);
336
337 // append additional dbus call paramaters
338 method.append(i_message, i_severity, io_additional, i_ffdc);
339
340 // using system dbus
341 auto response = bus.call(method);
342
343 // reply will be tuple containing bmc log id, platform log id
344 std::tuple<uint32_t, uint32_t> reply = {0, 0};
345
346 // parse dbus response into reply
347 response.read(reply);
348 plid = std::get<1>(reply); // platform log id is tuple "second"
349 }
350 catch (const sdbusplus::exception::SdBusError& e)
351 {
352 trace::err("createPel exception");
353 trace::err(e.what());
354 }
355 }
356
357 return plid; // platform log id or 0
358}
359
Caleb Palmer626270a2022-02-21 11:05:08 -0600360MachineType getMachineType()
361{
362 // default to Rainier 2S4U
363 MachineType machineType = MachineType::Rainier_2S4U;
364
365 // The return value of the dbus operation is a vector of 4 uint8_ts
366 std::vector<uint8_t> ids;
367
368 constexpr auto interface = "com.ibm.ipzvpd.VSBP";
369
370 DBusService service;
371 DBusPath path;
372
373 if (0 == find(interface, path, service))
374 {
375 DBusValue value;
376
377 // Machine ID is given from the "IM" keyword
378 constexpr auto property = "IM";
379
380 if (0 == getProperty(interface, path, service, property, value))
381 {
382 // return value is a variant, ID value is a vector of 4 uint8_ts
383 ids = std::get<std::vector<uint8_t>>(value);
384
385 // Convert the returned ID value to a hex string to determine
386 // machine type. The hex values corresponding to the machine type
387 // are defined in /openbmc/openpower-vpd-parser/const.hpp
388 // RAINIER_2S4U == 0x50001000
389 // RAINIER_2S2U == 0x50001001
390 // RAINIER_1S4U == 0x50001002
391 // RAINIER_1S2U == 0x50001003
392 // EVEREST == 0x50003000
393 try
394 {
395 // Format the vector into a single hex string to compare to.
396 std::string hexId =
397 fmt::format("0x{:02x}{:02x}{:02x}{:02x}", ids.at(0),
398 ids.at(1), ids.at(2), ids.at(3));
399
400 std::map<std::string, MachineType> typeMap = {
401 {"0x50001000", MachineType::Rainier_2S4U},
402 {"0x50001001", MachineType::Rainier_2S2U},
403 {"0x50001002", MachineType::Rainier_1S4U},
404 {"0x50001003", MachineType::Rainier_1S2U},
405 {"0x50003000", MachineType::Everest},
406 };
407
408 machineType = typeMap.at(hexId);
409 }
410 catch (const std::out_of_range& e)
411 {
412 trace::err("Out of range exception caught from returned "
413 "machine ID.");
414 for (const auto& id : ids)
415 {
416 trace::err("Returned Machine ID value: 0x%x", id);
417 }
418 throw;
419 }
420 }
421 }
422 else
423 {
424 throw std::invalid_argument(
425 "Unable to find dbus service to get machine type.");
426 }
427
428 return machineType;
429}
430
Ben Tyner324234b2021-06-28 17:01:17 -0500431} // namespace dbus
432
433} // namespace util