blob: 57668d8704c1d35695c4a6c24e8158b40743b599 [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
Riya Dixit49cfb132023-03-02 04:26:53 -06005#include <phosphor-logging/lg2.hpp>
6
Sampa Misra032bd502019-03-06 05:03:22 -06007#include <array>
8#include <chrono>
9#include <ctime>
Sampa Misra032bd502019-03-06 05:03:22 -060010#include <stdexcept>
11#include <string>
12#include <variant>
13#include <vector>
14
Riya Dixit49cfb132023-03-02 04:26:53 -060015PHOSPHOR_LOG2_USING;
16
Brad Bishop5079ac42021-08-19 18:35:06 -040017using namespace pldm::utils;
18
Sampa Misra032bd502019-03-06 05:03:22 -060019namespace pldm
20{
Sampa Misra032bd502019-03-06 05:03:22 -060021namespace responder
22{
Sampa Misra032bd502019-03-06 05:03:22 -060023namespace utils
24{
Sampa Misra032bd502019-03-06 05:03:22 -060025void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
26 uint8_t& hours, uint8_t& day, uint8_t& month,
27 uint16_t& year)
28{
29 auto t = time_t(timeSec);
30 auto time = localtime(&t);
31
George Liu83409572019-12-24 18:42:54 +080032 seconds = pldm::utils::decimalToBcd(time->tm_sec);
33 minutes = pldm::utils::decimalToBcd(time->tm_min);
34 hours = pldm::utils::decimalToBcd(time->tm_hour);
35 day = pldm::utils::decimalToBcd(time->tm_mday);
Patrick Williams16c2a0a2024-08-16 15:20:59 -040036 month = pldm::utils::decimalToBcd(
37 time->tm_mon + 1); // The number of months in the range
38 // 0 to 11.PLDM expects range 1 to 12
39 year = pldm::utils::decimalToBcd(
40 time->tm_year + 1900); // The number of years since 1900
Sampa Misra032bd502019-03-06 05:03:22 -060041}
42
Xiaochao Ma60227a02019-12-04 09:00:12 +080043std::time_t timeToEpoch(uint8_t seconds, uint8_t minutes, uint8_t hours,
44 uint8_t day, uint8_t month, uint16_t year)
45{
46 struct std::tm stm;
47
48 stm.tm_year = year - 1900;
49 stm.tm_mon = month - 1;
50 stm.tm_mday = day;
51 stm.tm_hour = hours;
52 stm.tm_min = minutes;
53 stm.tm_sec = seconds;
54 stm.tm_isdst = -1;
55
56 // It will get the time in seconds since
57 // Epoch, 1970.1.1 00:00:00 +0000,UTC.
58 return timegm(&stm);
59}
60
Sampa Misra032bd502019-03-06 05:03:22 -060061} // namespace utils
62
Deepak Kodihallibc669f12019-11-28 08:52:07 -060063namespace bios
64{
John Wang6080aae2020-02-14 09:34:25 +080065using EpochTimeUS = uint64_t;
66
67DBusHandler dbusHandler;
68
Kamalkumar Patel3c50c822024-01-30 07:14:40 -060069Handler::Handler(
70 int fd, uint8_t eid, pldm::InstanceIdDb* instanceIdDb,
71 pldm::requester::Handler<pldm::requester::Request>* handler,
Archana Kakani62dd8ff2024-02-12 10:00:40 -060072 pldm::responder::platform_config::Handler* platformConfigHandler,
73 pldm::responder::bios::Callback requestPLDMServiceName) :
Tom Joseph7f839f92020-09-21 10:20:44 +053074 biosConfig(BIOS_JSONS_DIR, BIOS_TABLES_DIR, &dbusHandler, fd, eid,
Archana Kakani62dd8ff2024-02-12 10:00:40 -060075 instanceIdDb, handler, platformConfigHandler,
76 requestPLDMServiceName)
Deepak Kodihallid9fb1522019-11-28 10:06:34 -060077{
Delphine CC Chiud2e48992023-12-05 16:29:51 +080078 handlers.emplace(
79 PLDM_SET_DATE_TIME,
80 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040081 return this->setDateTime(request, payloadLength);
82 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080083 handlers.emplace(
84 PLDM_GET_DATE_TIME,
85 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040086 return this->getDateTime(request, payloadLength);
87 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080088 handlers.emplace(
89 PLDM_GET_BIOS_TABLE,
90 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040091 return this->getBIOSTable(request, payloadLength);
92 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080093 handlers.emplace(
94 PLDM_SET_BIOS_TABLE,
95 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040096 return this->setBIOSTable(request, payloadLength);
97 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080098 handlers.emplace(
99 PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE,
100 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400101 return this->getBIOSAttributeCurrentValueByHandle(request,
102 payloadLength);
103 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +0800104 handlers.emplace(
105 PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE,
106 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400107 return this->setBIOSAttributeCurrentValue(request, payloadLength);
108 });
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600109}
110
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600111Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -0600112{
113 uint8_t seconds = 0;
114 uint8_t minutes = 0;
115 uint8_t hours = 0;
116 uint8_t day = 0;
117 uint8_t month = 0;
118 uint16_t year = 0;
119
120 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liufd972642020-04-12 12:08:23 +0800121 constexpr auto bmcTimePath = "/xyz/openbmc_project/time/bmc";
vkaverapa6575b82019-04-03 05:33:52 -0500122 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
123 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
George Liu782d37f2020-01-24 09:02:17 +0800124 EpochTimeUS timeUsec;
Sampa Misra032bd502019-03-06 05:03:22 -0600125
Sampa Misra032bd502019-03-06 05:03:22 -0600126 try
127 {
George Liu782d37f2020-01-24 09:02:17 +0800128 timeUsec = pldm::utils::DBusHandler().getDbusProperty<EpochTimeUS>(
George Liufd972642020-04-12 12:08:23 +0800129 bmcTimePath, "Elapsed", timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -0600130 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500131 catch (const sdbusplus::exception_t& e)
Sampa Misra032bd502019-03-06 05:03:22 -0600132 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600133 error(
Riya Dixit89644442024-03-31 05:39:59 -0500134 "Error getting time from Elapsed property at path '{PATH}' on interface '{INTERFACE}': {ERROR}",
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500135 "PATH", bmcTimePath, "INTERFACE", timeInterface, "ERROR", e);
George Liufb8611d2019-12-06 10:14:15 +0800136 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
Sampa Misra032bd502019-03-06 05:03:22 -0600137 }
138
Sampa Misra032bd502019-03-06 05:03:22 -0600139 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
140 std::chrono::microseconds(timeUsec))
141 .count();
142
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600143 pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours,
144 day, month, year);
Sampa Misra032bd502019-03-06 05:03:22 -0600145
George Liufb8611d2019-12-06 10:14:15 +0800146 auto rc = encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS,
147 seconds, minutes, hours, day, month,
148 year, responsePtr);
149 if (rc != PLDM_SUCCESS)
150 {
151 return ccOnlyResponse(request, rc);
152 }
153
vkaverapa6575b82019-04-03 05:33:52 -0500154 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600155}
156
Xiaochao Ma60227a02019-12-04 09:00:12 +0800157Response Handler::setDateTime(const pldm_msg* request, size_t payloadLength)
158{
159 uint8_t seconds = 0;
160 uint8_t minutes = 0;
161 uint8_t hours = 0;
162 uint8_t day = 0;
163 uint8_t month = 0;
164 uint16_t year = 0;
165 std::time_t timeSec;
166
Pavithra Barithaya297720a2022-09-12 05:50:38 -0500167 constexpr auto timeSyncPath = "/xyz/openbmc_project/time/sync_method";
168 constexpr auto timeSyncInterface =
169 "xyz.openbmc_project.Time.Synchronization";
170 constexpr auto timeSyncProperty = "TimeSyncMethod";
171
172 // The time is correct on BMC when in NTP mode, so we do not want to
173 // try and set the time again and cause potential time drifts.
174 try
175 {
176 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(
177 timeSyncPath, timeSyncProperty, timeSyncInterface);
178 const auto& mode = std::get<std::string>(propVal);
179
180 if (mode == "xyz.openbmc_project.Time.Synchronization.Method.NTP")
181 {
182 return ccOnlyResponse(request, PLDM_SUCCESS);
183 }
184 }
185 catch (const std::exception& e)
186 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600187 error(
Riya Dixit89644442024-03-31 05:39:59 -0500188 "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 -0600189 "TIME_SYNC_PATH", timeSyncPath, "SYNC_INTERFACE", timeSyncInterface,
Riya Dixit89644442024-03-31 05:39:59 -0500190 "SYNC_PROPERTY", timeSyncProperty, "ERROR", e);
Pavithra Barithaya297720a2022-09-12 05:50:38 -0500191 }
192
Xiaochao Ma60227a02019-12-04 09:00:12 +0800193 constexpr auto setTimeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liufd972642020-04-12 12:08:23 +0800194 constexpr auto setTimePath = "/xyz/openbmc_project/time/bmc";
Xiaochao Ma60227a02019-12-04 09:00:12 +0800195 constexpr auto timeSetPro = "Elapsed";
196
197 auto rc = decode_set_date_time_req(request, payloadLength, &seconds,
198 &minutes, &hours, &day, &month, &year);
199 if (rc != PLDM_SUCCESS)
200 {
201 return ccOnlyResponse(request, rc);
202 }
203 timeSec = pldm::responder::utils::timeToEpoch(seconds, minutes, hours, day,
204 month, year);
205 uint64_t timeUsec = std::chrono::duration_cast<std::chrono::microseconds>(
206 std::chrono::seconds(timeSec))
207 .count();
George Liu1e44c732020-02-28 20:20:06 +0800208 PropertyValue value{timeUsec};
Xiaochao Ma60227a02019-12-04 09:00:12 +0800209 try
210 {
George Liu1e44c732020-02-28 20:20:06 +0800211 DBusMapping dbusMapping{setTimePath, setTimeInterface, timeSetPro,
212 "uint64_t"};
213 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
Xiaochao Ma60227a02019-12-04 09:00:12 +0800214 }
Patrick Williams51330582021-10-06 12:48:56 -0500215 catch (const std::exception& e)
Xiaochao Ma60227a02019-12-04 09:00:12 +0800216 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600217 error(
Riya Dixit89644442024-03-31 05:39:59 -0500218 "Failed to set time at {SET_TIME_PATH}, interface '{TIME_INTERFACE}' and error - {ERROR}",
Riya Dixit49cfb132023-03-02 04:26:53 -0600219 "SET_TIME_PATH", setTimePath, "TIME_INTERFACE", setTimeInterface,
Riya Dixit89644442024-03-31 05:39:59 -0500220 "ERROR", e);
Xiaochao Ma60227a02019-12-04 09:00:12 +0800221 return ccOnlyResponse(request, PLDM_ERROR);
222 }
223
224 return ccOnlyResponse(request, PLDM_SUCCESS);
225}
226
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600227Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength)
Sampa Misrab37be312019-07-03 02:26:41 -0500228{
John Wang6080aae2020-02-14 09:34:25 +0800229 uint32_t transferHandle{};
230 uint8_t transferOpFlag{};
231 uint8_t tableType{};
232
233 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
234 &transferOpFlag, &tableType);
235 if (rc != PLDM_SUCCESS)
236 {
237 return ccOnlyResponse(request, rc);
238 }
239
240 auto table =
241 biosConfig.getBIOSTable(static_cast<pldm_bios_table_types>(tableType));
242 if (!table)
243 {
244 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE);
245 }
246
247 Response response(sizeof(pldm_msg_hdr) +
248 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + table->size());
249 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
250
251 rc = encode_get_bios_table_resp(
252 request->hdr.instance_id, PLDM_SUCCESS, 0 /* nxtTransferHandle */,
253 PLDM_START_AND_END, table->data(), response.size(), responsePtr);
254 if (rc != PLDM_SUCCESS)
255 {
256 return ccOnlyResponse(request, rc);
257 }
Sampa Misrab37be312019-07-03 02:26:41 -0500258
259 return response;
260}
261
George Liu1b180d82020-07-23 14:01:58 +0800262Response Handler::setBIOSTable(const pldm_msg* request, size_t payloadLength)
263{
264 uint32_t transferHandle{};
265 uint8_t transferOpFlag{};
266 uint8_t tableType{};
267 struct variable_field field;
268
269 auto rc = decode_set_bios_table_req(request, payloadLength, &transferHandle,
270 &transferOpFlag, &tableType, &field);
271 if (rc != PLDM_SUCCESS)
272 {
273 return ccOnlyResponse(request, rc);
274 }
275
276 Table table(field.ptr, field.ptr + field.length);
277 rc = biosConfig.setBIOSTable(tableType, table);
278 if (rc != PLDM_SUCCESS)
279 {
280 return ccOnlyResponse(request, rc);
281 }
282
283 Response response(sizeof(pldm_msg_hdr) + PLDM_SET_BIOS_TABLE_RESP_BYTES);
284 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
285
286 rc = encode_set_bios_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
287 0 /* nxtTransferHandle */, responsePtr);
288 if (rc != PLDM_SUCCESS)
289 {
290 return ccOnlyResponse(request, rc);
291 }
292
293 return response;
294}
295
John Wang8721ed62019-12-05 14:44:43 +0800296Response Handler::getBIOSAttributeCurrentValueByHandle(const pldm_msg* request,
297 size_t payloadLength)
298{
299 uint32_t transferHandle;
300 uint8_t transferOpFlag;
301 uint16_t attributeHandle;
302
303 auto rc = decode_get_bios_attribute_current_value_by_handle_req(
304 request, payloadLength, &transferHandle, &transferOpFlag,
305 &attributeHandle);
306 if (rc != PLDM_SUCCESS)
307 {
308 return ccOnlyResponse(request, rc);
309 }
310
John Wang6080aae2020-02-14 09:34:25 +0800311 auto table = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
312 if (!table)
Deepak Kodihalli4976a682020-01-07 05:48:29 -0600313 {
314 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE);
315 }
316
John Wang8721ed62019-12-05 14:44:43 +0800317 auto entry = pldm_bios_table_attr_value_find_by_handle(
John Wang6080aae2020-02-14 09:34:25 +0800318 table->data(), table->size(), attributeHandle);
John Wang8721ed62019-12-05 14:44:43 +0800319 if (entry == nullptr)
320 {
321 return ccOnlyResponse(request, PLDM_INVALID_BIOS_ATTR_HANDLE);
322 }
323
John Wang8e877e02020-02-03 16:06:55 +0800324 auto entryLength = pldm_bios_table_attr_value_entry_length(entry);
John Wang8721ed62019-12-05 14:44:43 +0800325 Response response(sizeof(pldm_msg_hdr) +
326 PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES +
John Wang8e877e02020-02-03 16:06:55 +0800327 entryLength,
John Wang8721ed62019-12-05 14:44:43 +0800328 0);
329 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
George Liufb8611d2019-12-06 10:14:15 +0800330 rc = encode_get_bios_current_value_by_handle_resp(
John Wang8e877e02020-02-03 16:06:55 +0800331 request->hdr.instance_id, PLDM_SUCCESS, 0, PLDM_START_AND_END,
332 reinterpret_cast<const uint8_t*>(entry), entryLength, responsePtr);
George Liufb8611d2019-12-06 10:14:15 +0800333 if (rc != PLDM_SUCCESS)
334 {
335 return ccOnlyResponse(request, rc);
336 }
John Wang8721ed62019-12-05 14:44:43 +0800337
338 return response;
339}
340
John Wang42174882019-12-20 14:56:59 +0800341Response Handler::setBIOSAttributeCurrentValue(const pldm_msg* request,
342 size_t payloadLength)
343{
344 uint32_t transferHandle;
345 uint8_t transferOpFlag;
346 variable_field attributeField;
347
348 auto rc = decode_set_bios_attribute_current_value_req(
349 request, payloadLength, &transferHandle, &transferOpFlag,
350 &attributeField);
351 if (rc != PLDM_SUCCESS)
352 {
353 return ccOnlyResponse(request, rc);
354 }
355
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600356 rc = biosConfig.setAttrValue(attributeField.ptr, attributeField.length,
357 false);
John Wang42174882019-12-20 14:56:59 +0800358
Xiaochao Ma7a0d0722020-05-29 09:07:33 +0800359 Response response(
360 sizeof(pldm_msg_hdr) + PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES, 0);
361 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
362
363 encode_set_bios_attribute_current_value_resp(request->hdr.instance_id, rc,
364 0, responsePtr);
365
366 return response;
John Wang42174882019-12-20 14:56:59 +0800367}
368
John Wangf719f3b2020-01-17 08:46:22 +0800369} // namespace bios
Sampa Misra032bd502019-03-06 05:03:22 -0600370} // namespace responder
371} // namespace pldm