xref: /openbmc/pldm/libpldmresponder/bios.cpp (revision 33705fda)
1 #include "bios.hpp"
2 
3 #include "libpldmresponder/utils.hpp"
4 #include "registration.hpp"
5 #include "xyz/openbmc_project/Common/error.hpp"
6 
7 #include <array>
8 #include <chrono>
9 #include <ctime>
10 #include <iostream>
11 #include <phosphor-logging/log.hpp>
12 #include <stdexcept>
13 #include <string>
14 #include <variant>
15 #include <vector>
16 
17 namespace pldm
18 {
19 
20 using namespace phosphor::logging;
21 
22 using EpochTimeUS = uint64_t;
23 
24 constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
25 
26 namespace responder
27 {
28 
29 namespace bios
30 {
31 
32 void registerHandlers()
33 {
34     registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
35 }
36 
37 } // namespace bios
38 
39 namespace utils
40 {
41 
42 void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
43                     uint8_t& hours, uint8_t& day, uint8_t& month,
44                     uint16_t& year)
45 {
46     auto t = time_t(timeSec);
47     auto time = localtime(&t);
48 
49     seconds = decimalToBcd(time->tm_sec);
50     minutes = decimalToBcd(time->tm_min);
51     hours = decimalToBcd(time->tm_hour);
52     day = decimalToBcd(time->tm_mday);
53     month =
54         decimalToBcd(time->tm_mon + 1); // The number of months in the range
55                                         // 0 to 11.PLDM expects range 1 to 12
56     year = decimalToBcd(time->tm_year + 1900); // The number of years since 1900
57 }
58 
59 } // namespace utils
60 
61 Response getDateTime(const pldm_msg* request, size_t payloadLength)
62 {
63     uint8_t seconds = 0;
64     uint8_t minutes = 0;
65     uint8_t hours = 0;
66     uint8_t day = 0;
67     uint8_t month = 0;
68     uint16_t year = 0;
69 
70     constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
71     constexpr auto bmcTimePath = "/xyz/openbmc_project/time/bmc";
72     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
73     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
74     std::variant<EpochTimeUS> value;
75 
76     auto bus = sdbusplus::bus::new_default();
77     try
78     {
79         auto service = getService(bus, bmcTimePath, timeInterface);
80 
81         auto method = bus.new_method_call(service.c_str(), bmcTimePath,
82                                           dbusProperties, "Get");
83         method.append(timeInterface, "Elapsed");
84 
85         auto reply = bus.call(method);
86         reply.read(value);
87     }
88 
89     catch (std::exception& e)
90     {
91         log<level::ERR>("Error getting time", entry("PATH=%s", bmcTimePath),
92                         entry("TIME INTERACE=%s", timeInterface));
93 
94         encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
95                                   minutes, hours, day, month, year,
96                                   responsePtr);
97         return response;
98     }
99 
100     uint64_t timeUsec = std::get<EpochTimeUS>(value);
101 
102     uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
103                            std::chrono::microseconds(timeUsec))
104                            .count();
105 
106     utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
107 
108     encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
109                               minutes, hours, day, month, year, responsePtr);
110     return response;
111 }
112 
113 } // namespace responder
114 } // namespace pldm
115