blob: a6c0c993ef5880aea126d5fe829d9d81996e49dd [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,
74 pldm::responder::platform_config::Handler* platformConfigHandler) :
Tom Joseph7f839f92020-09-21 10:20:44 +053075 biosConfig(BIOS_JSONS_DIR, BIOS_TABLES_DIR, &dbusHandler, fd, eid,
Kamalkumar Patel3c50c822024-01-30 07:14:40 -060076 instanceIdDb, handler, platformConfigHandler)
Deepak Kodihallid9fb1522019-11-28 10:06:34 -060077{
John Wang6080aae2020-02-14 09:34:25 +080078 biosConfig.removeTables();
79 biosConfig.buildTables();
80
Delphine CC Chiud2e48992023-12-05 16:29:51 +080081 handlers.emplace(
82 PLDM_SET_DATE_TIME,
83 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -050084 return this->setDateTime(request, payloadLength);
85 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080086 handlers.emplace(
87 PLDM_GET_DATE_TIME,
88 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -050089 return this->getDateTime(request, payloadLength);
90 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080091 handlers.emplace(
92 PLDM_GET_BIOS_TABLE,
93 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -050094 return this->getBIOSTable(request, payloadLength);
95 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +080096 handlers.emplace(
97 PLDM_SET_BIOS_TABLE,
98 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -050099 return this->setBIOSTable(request, payloadLength);
100 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +0800101 handlers.emplace(
102 PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE,
103 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500104 return this->getBIOSAttributeCurrentValueByHandle(request,
105 payloadLength);
106 });
Delphine CC Chiud2e48992023-12-05 16:29:51 +0800107 handlers.emplace(
108 PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE,
109 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500110 return this->setBIOSAttributeCurrentValue(request, payloadLength);
111 });
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600112}
113
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600114Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -0600115{
116 uint8_t seconds = 0;
117 uint8_t minutes = 0;
118 uint8_t hours = 0;
119 uint8_t day = 0;
120 uint8_t month = 0;
121 uint16_t year = 0;
122
123 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liufd972642020-04-12 12:08:23 +0800124 constexpr auto bmcTimePath = "/xyz/openbmc_project/time/bmc";
vkaverapa6575b82019-04-03 05:33:52 -0500125 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
126 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
George Liu782d37f2020-01-24 09:02:17 +0800127 EpochTimeUS timeUsec;
Sampa Misra032bd502019-03-06 05:03:22 -0600128
Sampa Misra032bd502019-03-06 05:03:22 -0600129 try
130 {
George Liu782d37f2020-01-24 09:02:17 +0800131 timeUsec = pldm::utils::DBusHandler().getDbusProperty<EpochTimeUS>(
George Liufd972642020-04-12 12:08:23 +0800132 bmcTimePath, "Elapsed", timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -0600133 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500134 catch (const sdbusplus::exception_t& e)
Sampa Misra032bd502019-03-06 05:03:22 -0600135 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600136 error(
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500137 "Error getting time from Elapsed property at '{PATH}' on '{INTERFACE}': {ERROR}",
138 "PATH", bmcTimePath, "INTERFACE", timeInterface, "ERROR", e);
George Liufb8611d2019-12-06 10:14:15 +0800139 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
Sampa Misra032bd502019-03-06 05:03:22 -0600140 }
141
Sampa Misra032bd502019-03-06 05:03:22 -0600142 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
143 std::chrono::microseconds(timeUsec))
144 .count();
145
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600146 pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours,
147 day, month, year);
Sampa Misra032bd502019-03-06 05:03:22 -0600148
George Liufb8611d2019-12-06 10:14:15 +0800149 auto rc = encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS,
150 seconds, minutes, hours, day, month,
151 year, responsePtr);
152 if (rc != PLDM_SUCCESS)
153 {
154 return ccOnlyResponse(request, rc);
155 }
156
vkaverapa6575b82019-04-03 05:33:52 -0500157 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600158}
159
Xiaochao Ma60227a02019-12-04 09:00:12 +0800160Response Handler::setDateTime(const pldm_msg* request, size_t payloadLength)
161{
162 uint8_t seconds = 0;
163 uint8_t minutes = 0;
164 uint8_t hours = 0;
165 uint8_t day = 0;
166 uint8_t month = 0;
167 uint16_t year = 0;
168 std::time_t timeSec;
169
Pavithra Barithaya297720a2022-09-12 05:50:38 -0500170 constexpr auto timeSyncPath = "/xyz/openbmc_project/time/sync_method";
171 constexpr auto timeSyncInterface =
172 "xyz.openbmc_project.Time.Synchronization";
173 constexpr auto timeSyncProperty = "TimeSyncMethod";
174
175 // The time is correct on BMC when in NTP mode, so we do not want to
176 // try and set the time again and cause potential time drifts.
177 try
178 {
179 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(
180 timeSyncPath, timeSyncProperty, timeSyncInterface);
181 const auto& mode = std::get<std::string>(propVal);
182
183 if (mode == "xyz.openbmc_project.Time.Synchronization.Method.NTP")
184 {
185 return ccOnlyResponse(request, PLDM_SUCCESS);
186 }
187 }
188 catch (const std::exception& e)
189 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600190 error(
191 "Error getting the time sync property, PATH={TIME_SYNC_PATH} INTERFACE={SYNC_INTERFACE} PROPERTY={SYNC_PROP} ERROR={ERR_EXCEP}",
192 "TIME_SYNC_PATH", timeSyncPath, "SYNC_INTERFACE", timeSyncInterface,
193 "SYNC_PROP", timeSyncProperty, "ERR_EXCEP", e.what());
Pavithra Barithaya297720a2022-09-12 05:50:38 -0500194 }
195
Xiaochao Ma60227a02019-12-04 09:00:12 +0800196 constexpr auto setTimeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liufd972642020-04-12 12:08:23 +0800197 constexpr auto setTimePath = "/xyz/openbmc_project/time/bmc";
Xiaochao Ma60227a02019-12-04 09:00:12 +0800198 constexpr auto timeSetPro = "Elapsed";
199
200 auto rc = decode_set_date_time_req(request, payloadLength, &seconds,
201 &minutes, &hours, &day, &month, &year);
202 if (rc != PLDM_SUCCESS)
203 {
204 return ccOnlyResponse(request, rc);
205 }
206 timeSec = pldm::responder::utils::timeToEpoch(seconds, minutes, hours, day,
207 month, year);
208 uint64_t timeUsec = std::chrono::duration_cast<std::chrono::microseconds>(
209 std::chrono::seconds(timeSec))
210 .count();
George Liu1e44c732020-02-28 20:20:06 +0800211 PropertyValue value{timeUsec};
Xiaochao Ma60227a02019-12-04 09:00:12 +0800212 try
213 {
George Liu1e44c732020-02-28 20:20:06 +0800214 DBusMapping dbusMapping{setTimePath, setTimeInterface, timeSetPro,
215 "uint64_t"};
216 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
Xiaochao Ma60227a02019-12-04 09:00:12 +0800217 }
Patrick Williams51330582021-10-06 12:48:56 -0500218 catch (const std::exception& e)
Xiaochao Ma60227a02019-12-04 09:00:12 +0800219 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600220 error(
221 "Error Setting time,PATH={SET_TIME_PATH} TIME INTERFACE={TIME_INTERFACE} ERROR={ERR_EXCEP}",
222 "SET_TIME_PATH", setTimePath, "TIME_INTERFACE", setTimeInterface,
223 "ERR_EXCEP", e.what());
Xiaochao Ma60227a02019-12-04 09:00:12 +0800224 return ccOnlyResponse(request, PLDM_ERROR);
225 }
226
227 return ccOnlyResponse(request, PLDM_SUCCESS);
228}
229
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600230Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength)
Sampa Misrab37be312019-07-03 02:26:41 -0500231{
John Wang6080aae2020-02-14 09:34:25 +0800232 uint32_t transferHandle{};
233 uint8_t transferOpFlag{};
234 uint8_t tableType{};
235
236 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
237 &transferOpFlag, &tableType);
238 if (rc != PLDM_SUCCESS)
239 {
240 return ccOnlyResponse(request, rc);
241 }
242
243 auto table =
244 biosConfig.getBIOSTable(static_cast<pldm_bios_table_types>(tableType));
245 if (!table)
246 {
247 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE);
248 }
249
250 Response response(sizeof(pldm_msg_hdr) +
251 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + table->size());
252 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
253
254 rc = encode_get_bios_table_resp(
255 request->hdr.instance_id, PLDM_SUCCESS, 0 /* nxtTransferHandle */,
256 PLDM_START_AND_END, table->data(), response.size(), responsePtr);
257 if (rc != PLDM_SUCCESS)
258 {
259 return ccOnlyResponse(request, rc);
260 }
Sampa Misrab37be312019-07-03 02:26:41 -0500261
262 return response;
263}
264
George Liu1b180d82020-07-23 14:01:58 +0800265Response Handler::setBIOSTable(const pldm_msg* request, size_t payloadLength)
266{
267 uint32_t transferHandle{};
268 uint8_t transferOpFlag{};
269 uint8_t tableType{};
270 struct variable_field field;
271
272 auto rc = decode_set_bios_table_req(request, payloadLength, &transferHandle,
273 &transferOpFlag, &tableType, &field);
274 if (rc != PLDM_SUCCESS)
275 {
276 return ccOnlyResponse(request, rc);
277 }
278
279 Table table(field.ptr, field.ptr + field.length);
280 rc = biosConfig.setBIOSTable(tableType, table);
281 if (rc != PLDM_SUCCESS)
282 {
283 return ccOnlyResponse(request, rc);
284 }
285
286 Response response(sizeof(pldm_msg_hdr) + PLDM_SET_BIOS_TABLE_RESP_BYTES);
287 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
288
289 rc = encode_set_bios_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
290 0 /* nxtTransferHandle */, responsePtr);
291 if (rc != PLDM_SUCCESS)
292 {
293 return ccOnlyResponse(request, rc);
294 }
295
296 return response;
297}
298
John Wang8721ed62019-12-05 14:44:43 +0800299Response Handler::getBIOSAttributeCurrentValueByHandle(const pldm_msg* request,
300 size_t payloadLength)
301{
302 uint32_t transferHandle;
303 uint8_t transferOpFlag;
304 uint16_t attributeHandle;
305
306 auto rc = decode_get_bios_attribute_current_value_by_handle_req(
307 request, payloadLength, &transferHandle, &transferOpFlag,
308 &attributeHandle);
309 if (rc != PLDM_SUCCESS)
310 {
311 return ccOnlyResponse(request, rc);
312 }
313
John Wang6080aae2020-02-14 09:34:25 +0800314 auto table = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
315 if (!table)
Deepak Kodihalli4976a682020-01-07 05:48:29 -0600316 {
317 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE);
318 }
319
John Wang8721ed62019-12-05 14:44:43 +0800320 auto entry = pldm_bios_table_attr_value_find_by_handle(
John Wang6080aae2020-02-14 09:34:25 +0800321 table->data(), table->size(), attributeHandle);
John Wang8721ed62019-12-05 14:44:43 +0800322 if (entry == nullptr)
323 {
324 return ccOnlyResponse(request, PLDM_INVALID_BIOS_ATTR_HANDLE);
325 }
326
John Wang8e877e02020-02-03 16:06:55 +0800327 auto entryLength = pldm_bios_table_attr_value_entry_length(entry);
John Wang8721ed62019-12-05 14:44:43 +0800328 Response response(sizeof(pldm_msg_hdr) +
329 PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES +
John Wang8e877e02020-02-03 16:06:55 +0800330 entryLength,
John Wang8721ed62019-12-05 14:44:43 +0800331 0);
332 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
George Liufb8611d2019-12-06 10:14:15 +0800333 rc = encode_get_bios_current_value_by_handle_resp(
John Wang8e877e02020-02-03 16:06:55 +0800334 request->hdr.instance_id, PLDM_SUCCESS, 0, PLDM_START_AND_END,
335 reinterpret_cast<const uint8_t*>(entry), entryLength, responsePtr);
George Liufb8611d2019-12-06 10:14:15 +0800336 if (rc != PLDM_SUCCESS)
337 {
338 return ccOnlyResponse(request, rc);
339 }
John Wang8721ed62019-12-05 14:44:43 +0800340
341 return response;
342}
343
John Wang42174882019-12-20 14:56:59 +0800344Response Handler::setBIOSAttributeCurrentValue(const pldm_msg* request,
345 size_t payloadLength)
346{
347 uint32_t transferHandle;
348 uint8_t transferOpFlag;
349 variable_field attributeField;
350
351 auto rc = decode_set_bios_attribute_current_value_req(
352 request, payloadLength, &transferHandle, &transferOpFlag,
353 &attributeField);
354 if (rc != PLDM_SUCCESS)
355 {
356 return ccOnlyResponse(request, rc);
357 }
358
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600359 rc = biosConfig.setAttrValue(attributeField.ptr, attributeField.length,
360 false);
John Wang42174882019-12-20 14:56:59 +0800361
Xiaochao Ma7a0d0722020-05-29 09:07:33 +0800362 Response response(
363 sizeof(pldm_msg_hdr) + PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES, 0);
364 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
365
366 encode_set_bios_attribute_current_value_resp(request->hdr.instance_id, rc,
367 0, responsePtr);
368
369 return response;
John Wang42174882019-12-20 14:56:59 +0800370}
371
John Wangf719f3b2020-01-17 08:46:22 +0800372} // namespace bios
Sampa Misra032bd502019-03-06 05:03:22 -0600373} // namespace responder
374} // namespace pldm