blob: d97229d7dd1665a0dd3d0f1ea9655775110daed5 [file] [log] [blame]
Sampa Misra032bd502019-03-06 05:03:22 -06001#include "bios.hpp"
2
Deepak Kodihallid130e1a2020-06-17 05:55:32 -05003#include "common/utils.hpp"
Sampa Misra032bd502019-03-06 05:03:22 -06004
Xiaochao Ma60227a02019-12-04 09:00:12 +08005#include <time.h>
6
Riya Dixit49cfb132023-03-02 04:26:53 -06007#include <phosphor-logging/lg2.hpp>
8
Sampa Misra032bd502019-03-06 05:03:22 -06009#include <array>
10#include <chrono>
11#include <ctime>
Sampa Misra032bd502019-03-06 05:03:22 -060012#include <stdexcept>
13#include <string>
14#include <variant>
15#include <vector>
16
Riya Dixit49cfb132023-03-02 04:26:53 -060017PHOSPHOR_LOG2_USING;
18
Brad Bishop5079ac42021-08-19 18:35:06 -040019using namespace pldm::utils;
20
Sampa Misra032bd502019-03-06 05:03:22 -060021namespace pldm
22{
Sampa Misra032bd502019-03-06 05:03:22 -060023namespace responder
24{
Sampa Misra032bd502019-03-06 05:03:22 -060025namespace utils
26{
Sampa Misra032bd502019-03-06 05:03:22 -060027void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
28 uint8_t& hours, uint8_t& day, uint8_t& month,
29 uint16_t& year)
30{
31 auto t = time_t(timeSec);
32 auto time = localtime(&t);
33
George Liu83409572019-12-24 18:42:54 +080034 seconds = pldm::utils::decimalToBcd(time->tm_sec);
35 minutes = pldm::utils::decimalToBcd(time->tm_min);
36 hours = pldm::utils::decimalToBcd(time->tm_hour);
37 day = pldm::utils::decimalToBcd(time->tm_mday);
38 month = pldm::utils::decimalToBcd(time->tm_mon +
39 1); // The number of months in the range
40 // 0 to 11.PLDM expects range 1 to 12
41 year = pldm::utils::decimalToBcd(time->tm_year +
42 1900); // The number of years since 1900
Sampa Misra032bd502019-03-06 05:03:22 -060043}
44
Xiaochao Ma60227a02019-12-04 09:00:12 +080045std::time_t timeToEpoch(uint8_t seconds, uint8_t minutes, uint8_t hours,
46 uint8_t day, uint8_t month, uint16_t year)
47{
48 struct std::tm stm;
49
50 stm.tm_year = year - 1900;
51 stm.tm_mon = month - 1;
52 stm.tm_mday = day;
53 stm.tm_hour = hours;
54 stm.tm_min = minutes;
55 stm.tm_sec = seconds;
56 stm.tm_isdst = -1;
57
58 // It will get the time in seconds since
59 // Epoch, 1970.1.1 00:00:00 +0000,UTC.
60 return timegm(&stm);
61}
62
Sampa Misra032bd502019-03-06 05:03:22 -060063} // namespace utils
64
Deepak Kodihallibc669f12019-11-28 08:52:07 -060065namespace bios
66{
John Wang6080aae2020-02-14 09:34:25 +080067using EpochTimeUS = uint64_t;
68
69DBusHandler dbusHandler;
70
Kamalkumar Patel3c50c822024-01-30 07:14:40 -060071Handler::Handler(
72 int fd, uint8_t eid, pldm::InstanceIdDb* instanceIdDb,
73 pldm::requester::Handler<pldm::requester::Request>* handler,
Archana Kakani62dd8ff2024-02-12 10:00:40 -060074 pldm::responder::platform_config::Handler* platformConfigHandler,
75 pldm::responder::bios::Callback requestPLDMServiceName) :
Tom Joseph7f839f92020-09-21 10:20:44 +053076 biosConfig(BIOS_JSONS_DIR, BIOS_TABLES_DIR, &dbusHandler, fd, eid,
Archana Kakani62dd8ff2024-02-12 10:00:40 -060077 instanceIdDb, handler, platformConfigHandler,
78 requestPLDMServiceName)
Deepak Kodihallid9fb1522019-11-28 10:06:34 -060079{
Delphine CC Chiud2e48992023-12-05 16:29:51 +080080 handlers.emplace(
81 PLDM_SET_DATE_TIME,
82 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -050083 return this->setDateTime(request, payloadLength);
84 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080085 handlers.emplace(
86 PLDM_GET_DATE_TIME,
87 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -050088 return this->getDateTime(request, payloadLength);
89 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080090 handlers.emplace(
91 PLDM_GET_BIOS_TABLE,
92 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -050093 return this->getBIOSTable(request, payloadLength);
94 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080095 handlers.emplace(
96 PLDM_SET_BIOS_TABLE,
97 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -050098 return this->setBIOSTable(request, payloadLength);
99 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +0800100 handlers.emplace(
101 PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE,
102 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500103 return this->getBIOSAttributeCurrentValueByHandle(request,
104 payloadLength);
105 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +0800106 handlers.emplace(
107 PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE,
108 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500109 return this->setBIOSAttributeCurrentValue(request, payloadLength);
110 });
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600111}
112
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600113Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -0600114{
115 uint8_t seconds = 0;
116 uint8_t minutes = 0;
117 uint8_t hours = 0;
118 uint8_t day = 0;
119 uint8_t month = 0;
120 uint16_t year = 0;
121
122 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liufd972642020-04-12 12:08:23 +0800123 constexpr auto bmcTimePath = "/xyz/openbmc_project/time/bmc";
vkaverapa6575b82019-04-03 05:33:52 -0500124 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
125 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
George Liu782d37f2020-01-24 09:02:17 +0800126 EpochTimeUS timeUsec;
Sampa Misra032bd502019-03-06 05:03:22 -0600127
Sampa Misra032bd502019-03-06 05:03:22 -0600128 try
129 {
George Liu782d37f2020-01-24 09:02:17 +0800130 timeUsec = pldm::utils::DBusHandler().getDbusProperty<EpochTimeUS>(
George Liufd972642020-04-12 12:08:23 +0800131 bmcTimePath, "Elapsed", timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -0600132 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500133 catch (const sdbusplus::exception_t& e)
Sampa Misra032bd502019-03-06 05:03:22 -0600134 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600135 error(
Riya Dixit89644442024-03-31 05:39:59 -0500136 "Error getting time from Elapsed property at path '{PATH}' on interface '{INTERFACE}': {ERROR}",
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500137 "PATH", bmcTimePath, "INTERFACE", timeInterface, "ERROR", e);
George Liufb8611d2019-12-06 10:14:15 +0800138 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
Sampa Misra032bd502019-03-06 05:03:22 -0600139 }
140
Sampa Misra032bd502019-03-06 05:03:22 -0600141 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
142 std::chrono::microseconds(timeUsec))
143 .count();
144
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600145 pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours,
146 day, month, year);
Sampa Misra032bd502019-03-06 05:03:22 -0600147
George Liufb8611d2019-12-06 10:14:15 +0800148 auto rc = encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS,
149 seconds, minutes, hours, day, month,
150 year, responsePtr);
151 if (rc != PLDM_SUCCESS)
152 {
153 return ccOnlyResponse(request, rc);
154 }
155
vkaverapa6575b82019-04-03 05:33:52 -0500156 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600157}
158
Xiaochao Ma60227a02019-12-04 09:00:12 +0800159Response Handler::setDateTime(const pldm_msg* request, size_t payloadLength)
160{
161 uint8_t seconds = 0;
162 uint8_t minutes = 0;
163 uint8_t hours = 0;
164 uint8_t day = 0;
165 uint8_t month = 0;
166 uint16_t year = 0;
167 std::time_t timeSec;
168
Pavithra Barithaya297720a2022-09-12 05:50:38 -0500169 constexpr auto timeSyncPath = "/xyz/openbmc_project/time/sync_method";
170 constexpr auto timeSyncInterface =
171 "xyz.openbmc_project.Time.Synchronization";
172 constexpr auto timeSyncProperty = "TimeSyncMethod";
173
174 // The time is correct on BMC when in NTP mode, so we do not want to
175 // try and set the time again and cause potential time drifts.
176 try
177 {
178 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(
179 timeSyncPath, timeSyncProperty, timeSyncInterface);
180 const auto& mode = std::get<std::string>(propVal);
181
182 if (mode == "xyz.openbmc_project.Time.Synchronization.Method.NTP")
183 {
184 return ccOnlyResponse(request, PLDM_SUCCESS);
185 }
186 }
187 catch (const std::exception& e)
188 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600189 error(
Riya Dixit89644442024-03-31 05:39:59 -0500190 "Failed to get the time sync property from path {TIME_SYNC_PATH}, interface '{SYNC_INTERFACE}' and property '{SYNC_PROPERTY}', error - '{ERROR}'",
Riya Dixit49cfb132023-03-02 04:26:53 -0600191 "TIME_SYNC_PATH", timeSyncPath, "SYNC_INTERFACE", timeSyncInterface,
Riya Dixit89644442024-03-31 05:39:59 -0500192 "SYNC_PROPERTY", timeSyncProperty, "ERROR", e);
Pavithra Barithaya297720a2022-09-12 05:50:38 -0500193 }
194
Xiaochao Ma60227a02019-12-04 09:00:12 +0800195 constexpr auto setTimeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liufd972642020-04-12 12:08:23 +0800196 constexpr auto setTimePath = "/xyz/openbmc_project/time/bmc";
Xiaochao Ma60227a02019-12-04 09:00:12 +0800197 constexpr auto timeSetPro = "Elapsed";
198
199 auto rc = decode_set_date_time_req(request, payloadLength, &seconds,
200 &minutes, &hours, &day, &month, &year);
201 if (rc != PLDM_SUCCESS)
202 {
203 return ccOnlyResponse(request, rc);
204 }
205 timeSec = pldm::responder::utils::timeToEpoch(seconds, minutes, hours, day,
206 month, year);
207 uint64_t timeUsec = std::chrono::duration_cast<std::chrono::microseconds>(
208 std::chrono::seconds(timeSec))
209 .count();
George Liu1e44c732020-02-28 20:20:06 +0800210 PropertyValue value{timeUsec};
Xiaochao Ma60227a02019-12-04 09:00:12 +0800211 try
212 {
George Liu1e44c732020-02-28 20:20:06 +0800213 DBusMapping dbusMapping{setTimePath, setTimeInterface, timeSetPro,
214 "uint64_t"};
215 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
Xiaochao Ma60227a02019-12-04 09:00:12 +0800216 }
Patrick Williams51330582021-10-06 12:48:56 -0500217 catch (const std::exception& e)
Xiaochao Ma60227a02019-12-04 09:00:12 +0800218 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600219 error(
Riya Dixit89644442024-03-31 05:39:59 -0500220 "Failed to set time at {SET_TIME_PATH}, interface '{TIME_INTERFACE}' and error - {ERROR}",
Riya Dixit49cfb132023-03-02 04:26:53 -0600221 "SET_TIME_PATH", setTimePath, "TIME_INTERFACE", setTimeInterface,
Riya Dixit89644442024-03-31 05:39:59 -0500222 "ERROR", e);
Xiaochao Ma60227a02019-12-04 09:00:12 +0800223 return ccOnlyResponse(request, PLDM_ERROR);
224 }
225
226 return ccOnlyResponse(request, PLDM_SUCCESS);
227}
228
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600229Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength)
Sampa Misrab37be312019-07-03 02:26:41 -0500230{
John Wang6080aae2020-02-14 09:34:25 +0800231 uint32_t transferHandle{};
232 uint8_t transferOpFlag{};
233 uint8_t tableType{};
234
235 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
236 &transferOpFlag, &tableType);
237 if (rc != PLDM_SUCCESS)
238 {
239 return ccOnlyResponse(request, rc);
240 }
241
242 auto table =
243 biosConfig.getBIOSTable(static_cast<pldm_bios_table_types>(tableType));
244 if (!table)
245 {
246 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE);
247 }
248
249 Response response(sizeof(pldm_msg_hdr) +
250 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + table->size());
251 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
252
253 rc = encode_get_bios_table_resp(
254 request->hdr.instance_id, PLDM_SUCCESS, 0 /* nxtTransferHandle */,
255 PLDM_START_AND_END, table->data(), response.size(), responsePtr);
256 if (rc != PLDM_SUCCESS)
257 {
258 return ccOnlyResponse(request, rc);
259 }
Sampa Misrab37be312019-07-03 02:26:41 -0500260
261 return response;
262}
263
George Liu1b180d82020-07-23 14:01:58 +0800264Response Handler::setBIOSTable(const pldm_msg* request, size_t payloadLength)
265{
266 uint32_t transferHandle{};
267 uint8_t transferOpFlag{};
268 uint8_t tableType{};
269 struct variable_field field;
270
271 auto rc = decode_set_bios_table_req(request, payloadLength, &transferHandle,
272 &transferOpFlag, &tableType, &field);
273 if (rc != PLDM_SUCCESS)
274 {
275 return ccOnlyResponse(request, rc);
276 }
277
278 Table table(field.ptr, field.ptr + field.length);
279 rc = biosConfig.setBIOSTable(tableType, table);
280 if (rc != PLDM_SUCCESS)
281 {
282 return ccOnlyResponse(request, rc);
283 }
284
285 Response response(sizeof(pldm_msg_hdr) + PLDM_SET_BIOS_TABLE_RESP_BYTES);
286 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
287
288 rc = encode_set_bios_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
289 0 /* nxtTransferHandle */, responsePtr);
290 if (rc != PLDM_SUCCESS)
291 {
292 return ccOnlyResponse(request, rc);
293 }
294
295 return response;
296}
297
John Wang8721ed62019-12-05 14:44:43 +0800298Response Handler::getBIOSAttributeCurrentValueByHandle(const pldm_msg* request,
299 size_t payloadLength)
300{
301 uint32_t transferHandle;
302 uint8_t transferOpFlag;
303 uint16_t attributeHandle;
304
305 auto rc = decode_get_bios_attribute_current_value_by_handle_req(
306 request, payloadLength, &transferHandle, &transferOpFlag,
307 &attributeHandle);
308 if (rc != PLDM_SUCCESS)
309 {
310 return ccOnlyResponse(request, rc);
311 }
312
John Wang6080aae2020-02-14 09:34:25 +0800313 auto table = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
314 if (!table)
Deepak Kodihalli4976a682020-01-07 05:48:29 -0600315 {
316 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE);
317 }
318
John Wang8721ed62019-12-05 14:44:43 +0800319 auto entry = pldm_bios_table_attr_value_find_by_handle(
John Wang6080aae2020-02-14 09:34:25 +0800320 table->data(), table->size(), attributeHandle);
John Wang8721ed62019-12-05 14:44:43 +0800321 if (entry == nullptr)
322 {
323 return ccOnlyResponse(request, PLDM_INVALID_BIOS_ATTR_HANDLE);
324 }
325
John Wang8e877e02020-02-03 16:06:55 +0800326 auto entryLength = pldm_bios_table_attr_value_entry_length(entry);
John Wang8721ed62019-12-05 14:44:43 +0800327 Response response(sizeof(pldm_msg_hdr) +
328 PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES +
John Wang8e877e02020-02-03 16:06:55 +0800329 entryLength,
John Wang8721ed62019-12-05 14:44:43 +0800330 0);
331 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
George Liufb8611d2019-12-06 10:14:15 +0800332 rc = encode_get_bios_current_value_by_handle_resp(
John Wang8e877e02020-02-03 16:06:55 +0800333 request->hdr.instance_id, PLDM_SUCCESS, 0, PLDM_START_AND_END,
334 reinterpret_cast<const uint8_t*>(entry), entryLength, responsePtr);
George Liufb8611d2019-12-06 10:14:15 +0800335 if (rc != PLDM_SUCCESS)
336 {
337 return ccOnlyResponse(request, rc);
338 }
John Wang8721ed62019-12-05 14:44:43 +0800339
340 return response;
341}
342
John Wang42174882019-12-20 14:56:59 +0800343Response Handler::setBIOSAttributeCurrentValue(const pldm_msg* request,
344 size_t payloadLength)
345{
346 uint32_t transferHandle;
347 uint8_t transferOpFlag;
348 variable_field attributeField;
349
350 auto rc = decode_set_bios_attribute_current_value_req(
351 request, payloadLength, &transferHandle, &transferOpFlag,
352 &attributeField);
353 if (rc != PLDM_SUCCESS)
354 {
355 return ccOnlyResponse(request, rc);
356 }
357
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600358 rc = biosConfig.setAttrValue(attributeField.ptr, attributeField.length,
359 false);
John Wang42174882019-12-20 14:56:59 +0800360
Xiaochao Ma7a0d0722020-05-29 09:07:33 +0800361 Response response(
362 sizeof(pldm_msg_hdr) + PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES, 0);
363 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
364
365 encode_set_bios_attribute_current_value_resp(request->hdr.instance_id, rc,
366 0, responsePtr);
367
368 return response;
John Wang42174882019-12-20 14:56:59 +0800369}
370
John Wangf719f3b2020-01-17 08:46:22 +0800371} // namespace bios
Sampa Misra032bd502019-03-06 05:03:22 -0600372} // namespace responder
373} // namespace pldm