blob: 8dbc80e441482787c35e9bab3fdb17d2316b0e57 [file] [log] [blame]
Sampa Misra032bd502019-03-06 05:03:22 -06001#include "bios.hpp"
2
3#include "libpldmresponder/utils.hpp"
Jinu Joy Thomasf666db12019-05-29 05:22:31 -05004#include "registration.hpp"
Sampa Misra032bd502019-03-06 05:03:22 -06005#include "xyz/openbmc_project/Common/error.hpp"
6
7#include <array>
Sampa Misrab37be312019-07-03 02:26:41 -05008#include <boost/crc.hpp>
Sampa Misra032bd502019-03-06 05:03:22 -06009#include <chrono>
10#include <ctime>
John Wang02700402019-10-06 16:34:29 +080011#include <memory>
Sampa Misrab37be312019-07-03 02:26:41 -050012#include <numeric>
13#include <phosphor-logging/elog-errors.hpp>
Deepak Kodihallic2feac92019-04-30 17:21:19 +053014#include <phosphor-logging/log.hpp>
Sampa Misra032bd502019-03-06 05:03:22 -060015#include <stdexcept>
16#include <string>
17#include <variant>
18#include <vector>
19
Sampa Misrab37be312019-07-03 02:26:41 -050020using namespace pldm::responder::bios;
21using namespace bios_parser;
Sampa Misrab37be312019-07-03 02:26:41 -050022
Sampa Misra032bd502019-03-06 05:03:22 -060023namespace pldm
24{
25
26using namespace phosphor::logging;
Sampa Misrab37be312019-07-03 02:26:41 -050027using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Sampa Misra032bd502019-03-06 05:03:22 -060028using EpochTimeUS = uint64_t;
Sampa Misrab37be312019-07-03 02:26:41 -050029using BIOSTableRow = std::vector<uint8_t>;
Carol Wangdc220c82019-08-26 13:31:31 +080030using BIOSJsonName = std::string;
Sampa Misra032bd502019-03-06 05:03:22 -060031
32constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
Sampa Misrab37be312019-07-03 02:26:41 -050033constexpr auto padChksumMax = 7;
Sampa Misra032bd502019-03-06 05:03:22 -060034
35namespace responder
36{
37
38namespace utils
39{
40
41void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
42 uint8_t& hours, uint8_t& day, uint8_t& month,
43 uint16_t& year)
44{
45 auto t = time_t(timeSec);
46 auto time = localtime(&t);
47
48 seconds = decimalToBcd(time->tm_sec);
49 minutes = decimalToBcd(time->tm_min);
50 hours = decimalToBcd(time->tm_hour);
51 day = decimalToBcd(time->tm_mday);
52 month =
53 decimalToBcd(time->tm_mon + 1); // The number of months in the range
54 // 0 to 11.PLDM expects range 1 to 12
55 year = decimalToBcd(time->tm_year + 1900); // The number of years since 1900
56}
57
John Wangc2938352019-09-30 13:58:41 +080058size_t getTableTotalsize(size_t sizeWithoutPad)
59{
60 auto padSize = getNumPadBytes(sizeWithoutPad);
61 return sizeWithoutPad + padSize + sizeof(uint32_t) /* checksum */;
62}
63
64void padAndChecksum(Table& table)
65{
66 auto padSize = getNumPadBytes(table.size());
67 table.insert(table.end(), padSize, 0);
68
69 boost::crc_32_type result;
70 size_t size = table.size();
71 result.process_bytes(table.data(), size);
72 uint32_t checkSum = result.checksum();
73 uint8_t* checkSumPtr = reinterpret_cast<uint8_t*>(&checkSum);
74 table.insert(table.end(), checkSumPtr, checkSumPtr + sizeof(checkSum));
75}
76
Sampa Misra032bd502019-03-06 05:03:22 -060077} // namespace utils
78
Deepak Kodihalli3c275e12019-09-21 06:39:39 -050079Response getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -060080{
81 uint8_t seconds = 0;
82 uint8_t minutes = 0;
83 uint8_t hours = 0;
84 uint8_t day = 0;
85 uint8_t month = 0;
86 uint16_t year = 0;
87
88 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liu408c3c42019-10-16 16:49:15 +080089 constexpr auto hostTimePath = "/xyz/openbmc_project/time/host";
vkaverapa6575b82019-04-03 05:33:52 -050090 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
91 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misra032bd502019-03-06 05:03:22 -060092 std::variant<EpochTimeUS> value;
93
94 auto bus = sdbusplus::bus::new_default();
95 try
96 {
George Liu408c3c42019-10-16 16:49:15 +080097 auto service = getService(bus, hostTimePath, timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -060098
George Liu408c3c42019-10-16 16:49:15 +080099 auto method = bus.new_method_call(service.c_str(), hostTimePath,
Sampa Misra032bd502019-03-06 05:03:22 -0600100 dbusProperties, "Get");
101 method.append(timeInterface, "Elapsed");
102
103 auto reply = bus.call(method);
104 reply.read(value);
105 }
106
107 catch (std::exception& e)
108 {
George Liu408c3c42019-10-16 16:49:15 +0800109 log<level::ERR>("Error getting time", entry("PATH=%s", hostTimePath),
Sampa Misra032bd502019-03-06 05:03:22 -0600110 entry("TIME INTERACE=%s", timeInterface));
111
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530112 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
113 minutes, hours, day, month, year,
114 responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500115 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600116 }
117
118 uint64_t timeUsec = std::get<EpochTimeUS>(value);
119
120 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
121 std::chrono::microseconds(timeUsec))
122 .count();
123
124 utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
125
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530126 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
127 minutes, hours, day, month, year, responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500128 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600129}
130
Sampa Misrab37be312019-07-03 02:26:41 -0500131/** @brief Generate the next attribute handle
132 *
133 * @return - uint16_t - next attribute handle
134 */
135AttributeHandle nextAttributeHandle()
136{
137 static AttributeHandle attrHdl = 0;
138 return attrHdl++;
139}
140
141/** @brief Generate the next string handle
142 * *
143 * @return - uint16_t - next string handle
144 */
145StringHandle nextStringHandle()
146{
147 static StringHandle strHdl = 0;
148 return strHdl++;
149}
150
151/** @brief Construct the BIOS string table
152 *
153 * @param[in] BIOSStringTable - the string table
154 * @param[in] transferHandle - transfer handle to identify part of transfer
155 * @param[in] transferOpFlag - flag to indicate which part of data being
156 * transferred
157 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500158 */
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500159Response getBIOSStringTable(BIOSTable& BIOSStringTable,
160 uint32_t /*transferHandle*/,
John Wange96e7e52019-10-05 17:47:30 +0800161 uint8_t /*transferOpFlag*/, uint8_t instanceID)
162
Sampa Misrab37be312019-07-03 02:26:41 -0500163{
164 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
165 0);
166 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
167
168 if (BIOSStringTable.isEmpty())
169 { // no persisted table, constructing fresh table and file
John Wange96e7e52019-10-05 17:47:30 +0800170 auto biosStrings = bios_parser::getStrings();
Sampa Misrab37be312019-07-03 02:26:41 -0500171 std::sort(biosStrings.begin(), biosStrings.end());
172 // remove all duplicate strings received from bios json
173 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
174 biosStrings.end());
175 size_t allStringsLen =
176 std::accumulate(biosStrings.begin(), biosStrings.end(), 0,
177 [](size_t sum, const std::string& elem) {
178 return sum + elem.size();
179 });
180 size_t sizeWithoutPad =
181 allStringsLen +
182 (biosStrings.size() * (sizeof(pldm_bios_string_table_entry) - 1));
John Wangc2938352019-09-30 13:58:41 +0800183 Table stringTable;
184 stringTable.reserve(utils::getTableTotalsize(sizeWithoutPad));
185
186 stringTable.resize(sizeWithoutPad);
187 auto tablePtr = stringTable.data();
Sampa Misrab37be312019-07-03 02:26:41 -0500188 for (const auto& elem : biosStrings)
189 {
190 auto stringPtr =
191 reinterpret_cast<struct pldm_bios_string_table_entry*>(
192 tablePtr);
193
194 stringPtr->string_handle = nextStringHandle();
195 stringPtr->string_length = elem.length();
196 memcpy(stringPtr->name, elem.c_str(), elem.length());
197 tablePtr += sizeof(stringPtr->string_handle) +
198 sizeof(stringPtr->string_length);
199 tablePtr += elem.length();
200 }
Sampa Misrab37be312019-07-03 02:26:41 -0500201
John Wangc2938352019-09-30 13:58:41 +0800202 utils::padAndChecksum(stringTable);
203 BIOSStringTable.store(stringTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500204 response.resize(sizeof(pldm_msg_hdr) +
205 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
John Wangc2938352019-09-30 13:58:41 +0800206 stringTable.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500207 0);
208 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
209 size_t respPayloadLength = response.size();
210 uint32_t nxtTransferHandle = 0;
211 uint8_t transferFlag = PLDM_START_AND_END;
212 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
213 transferFlag, stringTable.data(),
214 respPayloadLength, responsePtr);
215 }
216 else
217 { // persisted table present, constructing response
218 size_t respPayloadLength = response.size();
219 uint32_t nxtTransferHandle = 0;
220 uint8_t transferFlag = PLDM_START_AND_END;
221 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
222 transferFlag, nullptr, respPayloadLength,
223 responsePtr); // filling up the header here
224 BIOSStringTable.load(response);
225 }
226
227 return response;
228}
229
230/** @brief Find the string handle from the BIOS string table given the name
231 *
232 * @param[in] name - name of the BIOS string
233 * @param[in] BIOSStringTable - the string table
234 * @return - uint16_t - handle of the string
235 */
236StringHandle findStringHandle(const std::string& name,
237 const BIOSTable& BIOSStringTable)
238{
239 StringHandle hdl{};
240 Response response;
241 BIOSStringTable.load(response);
242
243 auto tableData = response.data();
244 size_t tableLen = response.size();
245 auto tableEntry =
246 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
247 while (1)
248 {
249 hdl = tableEntry->string_handle;
250 uint16_t len = tableEntry->string_length;
John Wangbe6b8022019-09-27 14:20:15 +0800251 if (name.compare(0, name.length(), tableEntry->name, len) == 0)
Sampa Misrab37be312019-07-03 02:26:41 -0500252 {
253 break;
254 }
255 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
256
257 if (std::distance(tableData, response.data() + tableLen) <=
258 padChksumMax)
259 {
260 log<level::ERR>("Reached end of BIOS string table,did not find the "
261 "handle for the string",
262 entry("STRING=%s", name.c_str()));
263 elog<InternalFailure>();
264 break;
265 }
266
267 tableEntry =
268 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
269 }
270 return hdl;
271}
272
273/** @brief Find the string name from the BIOS string table for a string handle
274 *
275 * @param[in] stringHdl - string handle
276 * @param[in] BIOSStringTable - the string table
277 *
278 * @return - std::string - name of the corresponding BIOS string
279 */
280std::string findStringName(StringHandle stringHdl,
281 const BIOSTable& BIOSStringTable)
282{
283 std::string name;
284 Response response;
285 BIOSStringTable.load(response);
286
287 auto tableData = response.data();
288 size_t tableLen = response.size();
289 auto tableEntry =
290 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
291 while (1)
292 {
293 StringHandle currHdl = tableEntry->string_handle;
294 uint16_t len = tableEntry->string_length;
295 if (currHdl == stringHdl)
296 {
297 name.resize(len);
298 memcpy(name.data(), tableEntry->name, len);
299 break;
300 }
301 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
302
303 if (std::distance(tableData, response.data() + tableLen) <=
304 padChksumMax)
305 {
306 log<level::ERR>("Reached end of BIOS string table,did not find "
307 "string name for handle",
308 entry("STRING_HANDLE=%d", stringHdl));
309 break;
310 }
311
312 tableEntry =
313 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
314 }
315 return name;
316}
317
318namespace bios_type_enum
319{
320
Carol Wangdc220c82019-08-26 13:31:31 +0800321using namespace bios_parser::bios_enum;
322
Sampa Misrab37be312019-07-03 02:26:41 -0500323/** @brief Find the indices into the array of the possible values of string
324 * handles for the current values.This is used in attribute value table
325 *
326 * @param[in] possiVals - vector of string handles comprising all the possible
327 * values for an attribute
328 * @param[in] currVals - vector of strings comprising all current values
329 * for an attribute
330 * @param[in] BIOSStringTable - the string table
331 *
332 * @return - std::vector<uint8_t> - indices into the array of the possible
333 * values of string handles
334 */
335std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
336 CurrentValues currVals,
337 const BIOSTable& BIOSStringTable)
338{
339 std::vector<uint8_t> stringIndices;
340
341 for (const auto& currVal : currVals)
342 {
343 StringHandle curHdl;
344 try
345 {
346 curHdl = findStringHandle(currVal, BIOSStringTable);
347 }
348 catch (InternalFailure& e)
349 {
350 log<level::ERR>("Exception fetching handle for the string",
351 entry("STRING=%s", currVal.c_str()));
352 continue;
353 }
354
355 uint8_t i = 0;
356 for (auto possiHdl : possiVals)
357 {
358 if (possiHdl == curHdl)
359 {
360 stringIndices.push_back(i);
361 break;
362 }
363 i++;
364 }
365 }
366 return stringIndices;
367}
368
369/** @brief Find the indices into the array of the possible values of string
370 * handles for the default values. This is used in attribute table
371 *
372 * @param[in] possiVals - vector of strings comprising all the possible values
373 * for an attribute
374 * @param[in] defVals - vector of strings comprising all the default values
375 * for an attribute
376 * @return - std::vector<uint8_t> - indices into the array of the possible
377 * values of string
378 */
379std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
380 const DefaultValues& defVals)
381{
382 std::vector<uint8_t> defHdls;
383 for (const auto& defs : defVals)
384 {
385 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
386 if (index != possiVals.end())
387 {
388 defHdls.push_back(index - possiVals.begin());
389 }
390 }
391
392 return defHdls;
393}
394
395/** @brief Construct the attibute table for BIOS type Enumeration and
396 * Enumeration ReadOnly
397 * @param[in] BIOSStringTable - the string table
398 * @param[in] biosJsonDir - path where the BIOS json files are present
Carol Wangdc220c82019-08-26 13:31:31 +0800399 * @param[in,out] attributeTable - the attribute table
Sampa Misrab37be312019-07-03 02:26:41 -0500400 *
Sampa Misrab37be312019-07-03 02:26:41 -0500401 */
John Wange96e7e52019-10-05 17:47:30 +0800402void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500403{
Sampa Misrab37be312019-07-03 02:26:41 -0500404 const auto& attributeMap = getValues();
Sampa Misrab37be312019-07-03 02:26:41 -0500405 StringHandle strHandle;
406
407 for (const auto& [key, value] : attributeMap)
408 {
409 try
410 {
411 strHandle = findStringHandle(key, BIOSStringTable);
412 }
413 catch (InternalFailure& e)
414 {
415 log<level::ERR>("Could not find handle for BIOS string",
416 entry("ATTRIBUTE=%s", key.c_str()));
417 continue;
418 }
419 uint8_t typeOfAttr = (std::get<0>(value))
420 ? PLDM_BIOS_ENUMERATION_READ_ONLY
421 : PLDM_BIOS_ENUMERATION;
422 PossibleValues possiVals = std::get<1>(value);
423 DefaultValues defVals = std::get<2>(value);
424 // both the possible and default values are stored in sorted manner to
425 // ease in fetching back/comparison
426 std::sort(possiVals.begin(), possiVals.end());
427 std::sort(defVals.begin(), defVals.end());
428
429 std::vector<StringHandle> possiValsByHdl;
430 for (const auto& elem : possiVals)
431 {
432 try
433 {
434 auto hdl = findStringHandle(elem, BIOSStringTable);
435 possiValsByHdl.push_back(std::move(hdl));
436 }
437 catch (InternalFailure& e)
438 {
439 log<level::ERR>("Could not find handle for BIOS string",
440 entry("STRING=%s", elem.c_str()));
441 continue;
442 }
443 }
444 auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
445
446 BIOSTableRow enumAttrTable(
447 (sizeof(struct pldm_bios_attr_table_entry) - 1) + sizeof(uint8_t) +
448 possiValsByHdl.size() * sizeof(uint16_t) + sizeof(uint8_t) +
449 defValsByHdl.size() * sizeof(uint8_t),
450 0);
451 BIOSTableRow::iterator it = enumAttrTable.begin();
452 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
453 enumAttrTable.data());
454 attrPtr->attr_handle = nextAttributeHandle();
455 attrPtr->attr_type = typeOfAttr;
456 attrPtr->string_handle = std::move(strHandle);
457 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
458 uint8_t numPossibleVals = possiValsByHdl.size();
459 std::copy_n(&numPossibleVals, sizeof(numPossibleVals), it);
460 std::advance(it, sizeof(numPossibleVals));
461 std::copy_n(reinterpret_cast<uint8_t*>(possiValsByHdl.data()),
462 sizeof(uint16_t) * possiValsByHdl.size(), it);
463 std::advance(
464 it, sizeof(uint16_t) *
465 possiValsByHdl.size()); // possible val handle is uint16_t
466 uint8_t numDefaultVals = defValsByHdl.size();
467 std::copy_n(&numDefaultVals, sizeof(numDefaultVals), it);
468 std::advance(it, sizeof(numDefaultVals));
469 std::copy(defValsByHdl.begin(), defValsByHdl.end(), it);
470 std::advance(it, defValsByHdl.size());
471
472 std::move(enumAttrTable.begin(), enumAttrTable.end(),
473 std::back_inserter(attributeTable));
474 }
Sampa Misrab37be312019-07-03 02:26:41 -0500475}
476
John Wang3ad21752019-10-06 16:42:21 +0800477void constructAttrValueEntry(
478 const struct pldm_bios_attr_table_entry* attrTableEntry,
479 const std::string& attrName, const BIOSTable& BIOSStringTable,
480 Table& attrValueTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500481{
John Wang3ad21752019-10-06 16:42:21 +0800482 CurrentValues currVals;
483 try
Sampa Misrab37be312019-07-03 02:26:41 -0500484 {
John Wang3ad21752019-10-06 16:42:21 +0800485 currVals = getAttrValue(attrName);
Sampa Misrab37be312019-07-03 02:26:41 -0500486 }
John Wang3ad21752019-10-06 16:42:21 +0800487 catch (const std::exception& e)
488 {
489 log<level::ERR>("getAttrValue returned error for attribute",
490 entry("NAME=%s", attrName.c_str()),
491 entry("ERROR=%s", e.what()));
492 return;
493 }
494 uint8_t pv_num =
495 pldm_bios_table_attr_entry_enum_decode_pv_num(attrTableEntry);
496 PossibleValuesByHandle pvHdls(pv_num, 0);
497 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrTableEntry,
498 pvHdls.data(), pv_num);
499 std::sort(currVals.begin(), currVals.end());
500
501 auto currValStrIndices = findStrIndices(pvHdls, currVals, BIOSStringTable);
502
503 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
504 currValStrIndices.size());
505 auto tableSize = attrValueTable.size();
506 attrValueTable.resize(tableSize + entryLength);
507 pldm_bios_table_attr_value_entry_encode_enum(
508 attrValueTable.data() + tableSize, entryLength,
509 attrTableEntry->attr_handle, attrTableEntry->attr_type,
510 currValStrIndices.size(), currValStrIndices.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500511}
512
513} // end namespace bios_type_enum
514
Carol Wangdc220c82019-08-26 13:31:31 +0800515namespace bios_type_string
516{
Carol Wang612f35b2019-08-26 17:14:26 +0800517
518using namespace bios_parser::bios_string;
519
Carol Wangdc220c82019-08-26 13:31:31 +0800520/** @brief Construct the attibute table for BIOS type String and
521 * String ReadOnly
522 * @param[in] BIOSStringTable - the string table
523 * @param[in] biosJsonDir - path where the BIOS json files are present
524 * @param[in,out] attributeTable - the attribute table
525 *
526 */
John Wange96e7e52019-10-05 17:47:30 +0800527void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800528{
Carol Wang612f35b2019-08-26 17:14:26 +0800529 const auto& attributeMap = getValues();
530 StringHandle strHandle;
531
532 for (const auto& [key, value] : attributeMap)
533 {
534 try
535 {
536 strHandle = findStringHandle(key, BIOSStringTable);
537 }
538 catch (InternalFailure& e)
539 {
540 log<level::ERR>("Could not find handle for BIOS string",
541 entry("ATTRIBUTE=%s", key.c_str()));
542 continue;
543 }
544
545 const auto& [type, strType, minStrLen, maxStrLen, defaultStrLen,
546 defaultStr] = value;
547 uint8_t typeOfAttr =
548 type ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
549
550 BIOSTableRow stringAttrTable(bios_parser::bios_string::attrTableSize +
551 defaultStr.size());
552 BIOSTableRow::iterator it = stringAttrTable.begin();
553 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
554 stringAttrTable.data());
555 attrPtr->attr_handle = nextAttributeHandle();
556 attrPtr->attr_type = typeOfAttr;
557 attrPtr->string_handle = strHandle;
558
559 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
560 std::copy_n(&strType, sizeof(uint8_t), it);
561 std::advance(it, sizeof(uint8_t));
562 std::copy_n(reinterpret_cast<const uint8_t*>(&minStrLen),
563 sizeof(uint16_t), it);
564 std::advance(it, sizeof(uint16_t));
565 std::copy_n(reinterpret_cast<const uint8_t*>(&maxStrLen),
566 sizeof(uint16_t), it);
567 std::advance(it, sizeof(uint16_t));
568 std::copy_n(reinterpret_cast<const uint8_t*>(&defaultStrLen),
569 sizeof(uint16_t), it);
570 std::advance(it, sizeof(uint16_t));
571 std::copy_n(defaultStr.data(), defaultStr.size(), it);
572 std::advance(it, defaultStr.size());
573
574 attributeTable.insert(attributeTable.end(), stringAttrTable.begin(),
575 stringAttrTable.end());
576 }
Carol Wangdc220c82019-08-26 13:31:31 +0800577}
Carol Wangb503f9e2019-09-02 16:34:10 +0800578
John Wang3ad21752019-10-06 16:42:21 +0800579void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
580 const std::string& attrName,
Carol Wangb503f9e2019-09-02 16:34:10 +0800581 const BIOSTable& BIOSStringTable,
John Wang3ad21752019-10-06 16:42:21 +0800582 Table& attrValueTable)
Carol Wangb503f9e2019-09-02 16:34:10 +0800583{
John Wang3ad21752019-10-06 16:42:21 +0800584 std::ignore = BIOSStringTable;
585 std::string currStr;
586 uint16_t currStrLen = 0;
587 try
Carol Wangb503f9e2019-09-02 16:34:10 +0800588 {
John Wang3ad21752019-10-06 16:42:21 +0800589 currStr = getAttrValue(attrName);
590 currStrLen = currStr.size();
Carol Wangb503f9e2019-09-02 16:34:10 +0800591 }
John Wang3ad21752019-10-06 16:42:21 +0800592 catch (const std::exception& e)
593 {
594 log<level::ERR>("getAttrValue returned error for attribute",
595 entry("NAME=%s", attrName.c_str()),
596 entry("ERROR=%s", e.what()));
597 return;
598 }
599 auto entryLength =
600 pldm_bios_table_attr_value_entry_encode_string_length(currStrLen);
601 auto tableSize = attrValueTable.size();
602 attrValueTable.resize(tableSize + entryLength);
603 pldm_bios_table_attr_value_entry_encode_string(
604 attrValueTable.data() + tableSize, entryLength,
605 attrTableEntry->attr_handle, attrTableEntry->attr_type, currStrLen,
606 currStr.c_str());
Carol Wangb503f9e2019-09-02 16:34:10 +0800607}
608
Carol Wangdc220c82019-08-26 13:31:31 +0800609} // end namespace bios_type_string
610
John Wang02700402019-10-06 16:34:29 +0800611void traverseBIOSAttrTable(const Table& biosAttrTable,
612 AttrTableEntryHandler handler)
613{
614 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
615 iter(pldm_bios_table_iter_create(biosAttrTable.data(),
616 biosAttrTable.size(),
617 PLDM_BIOS_ATTR_TABLE),
618 pldm_bios_table_iter_free);
619 while (!pldm_bios_table_iter_is_end(iter.get()))
620 {
621 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
622 try
623 {
624 handler(table_entry);
625 }
626 catch (const std::exception& e)
627 {
628 log<level::ERR>("handler fails when traversing BIOSAttrTable",
629 entry("ERROR=%s", e.what()));
630 }
631 pldm_bios_table_iter_next(iter.get());
632 }
633}
634
John Wange96e7e52019-10-05 17:47:30 +0800635using typeHandler = std::function<void(const BIOSTable& BIOSStringTable,
636 Table& attributeTable)>;
Carol Wangdc220c82019-08-26 13:31:31 +0800637std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
638 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
639 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}};
640
Sampa Misrab37be312019-07-03 02:26:41 -0500641/** @brief Construct the BIOS attribute table
642 *
643 * @param[in] BIOSAttributeTable - the attribute table
644 * @param[in] BIOSStringTable - the string table
645 * @param[in] transferHandle - transfer handle to identify part of transfer
646 * @param[in] transferOpFlag - flag to indicate which part of data being
647 * transferred
648 * @param[in] instanceID - instance ID to identify the command
649 * @param[in] biosJsonDir - path where the BIOS json files are present
650 */
651Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
652 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500653 uint32_t /*transferHandle*/,
654 uint8_t /*transferOpFlag*/, uint8_t instanceID,
655 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500656{
657 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
658 0);
659 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
660 uint32_t nxtTransferHandle = 0;
661 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500662
663 if (BIOSAttributeTable.isEmpty())
664 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800665 Table attributeTable;
666 fs::path dir(biosJsonDir);
667
668 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
669 it++)
670 {
671 fs::path file = dir / it->first;
672 if (fs::exists(file))
673 {
John Wange96e7e52019-10-05 17:47:30 +0800674 it->second(BIOSStringTable, attributeTable);
Carol Wangdc220c82019-08-26 13:31:31 +0800675 }
676 }
677
678 if (attributeTable.empty())
679 { // no available json file is found
680 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
681 nxtTransferHandle, transferFlag, nullptr,
682 response.size(), responsePtr);
683 return response;
684 }
John Wangc2938352019-09-30 13:58:41 +0800685 utils::padAndChecksum(attributeTable);
686 BIOSAttributeTable.store(attributeTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500687 response.resize(sizeof(pldm_msg_hdr) +
688 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
689 attributeTable.size());
690 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500691 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
692 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800693 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500694 }
695 else
696 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500697 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800698 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500699 responsePtr); // filling up the header here
700 BIOSAttributeTable.load(response);
701 }
702
703 return response;
704}
705
John Wang3ad21752019-10-06 16:42:21 +0800706using AttrValTableEntryConstructHandler =
707 std::function<void(const struct pldm_bios_attr_table_entry* tableEntry,
708 const std::string& attrName,
709 const BIOSTable& BIOSStringTable, Table& table)>;
710
711using AttrType = uint8_t;
712const std::map<AttrType, AttrValTableEntryConstructHandler>
713 AttrValTableConstructMap{
714 {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry},
715 {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry},
716 {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry},
717 {PLDM_BIOS_ENUMERATION_READ_ONLY,
718 bios_type_enum::constructAttrValueEntry},
719 };
720
721void constructAttrValueTableEntry(
722 const struct pldm_bios_attr_table_entry* attrEntry,
723 const BIOSTable& BIOSStringTable, Table& attributeValueTable)
724{
725 auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable);
726 if (attrName.empty())
727 {
728 log<level::ERR>("invalid string handle",
729 entry("STRING_HANDLE=%d", attrEntry->string_handle));
730 return;
731 }
732
733 AttrValTableConstructMap.at(attrEntry->attr_type)(
734 attrEntry, attrName, BIOSStringTable, attributeValueTable);
735}
736
Sampa Misrab37be312019-07-03 02:26:41 -0500737/** @brief Construct the BIOS attribute value table
738 *
739 * @param[in] BIOSAttributeValueTable - the attribute value table
740 * @param[in] BIOSAttributeTable - the attribute table
741 * @param[in] BIOSStringTable - the string table
742 * @param[in] transferHandle - transfer handle to identify part of transfer
743 * @param[in] transferOpFlag - flag to indicate which part of data being
744 * transferred
745 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500746 */
747Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
748 const BIOSTable& BIOSAttributeTable,
749 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500750 uint32_t& /*transferHandle*/,
751 uint8_t& /*transferOpFlag*/,
John Wang3ad21752019-10-06 16:42:21 +0800752 uint8_t instanceID)
Sampa Misrab37be312019-07-03 02:26:41 -0500753{
754 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
755 0);
756 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
757 uint32_t nxtTransferHandle = 0;
758 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500759
John Wang3ad21752019-10-06 16:42:21 +0800760 if (!BIOSAttributeValueTable.isEmpty())
761 {
Sampa Misrab37be312019-07-03 02:26:41 -0500762 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
John Wang3ad21752019-10-06 16:42:21 +0800763 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500764 responsePtr); // filling up the header here
765 BIOSAttributeValueTable.load(response);
John Wang3ad21752019-10-06 16:42:21 +0800766 return response;
Sampa Misrab37be312019-07-03 02:26:41 -0500767 }
768
John Wang3ad21752019-10-06 16:42:21 +0800769 Table attributeValueTable;
770 Table attributeTable;
771 BIOSAttributeTable.load(attributeTable);
772 traverseBIOSAttrTable(
773 attributeTable,
774 [&BIOSStringTable, &attributeValueTable](
775 const struct pldm_bios_attr_table_entry* tableEntry) {
776 constructAttrValueTableEntry(tableEntry, BIOSStringTable,
777 attributeValueTable);
778 });
779 if (attributeValueTable.empty())
780 {
781 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
782 nxtTransferHandle, transferFlag, nullptr,
783 response.size(), responsePtr);
784 return response;
785 }
786 utils::padAndChecksum(attributeValueTable);
787 BIOSAttributeValueTable.store(attributeValueTable);
788
789 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
790 attributeValueTable.size());
791 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
792 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
793 transferFlag, attributeValueTable.data(),
794 response.size(), responsePtr);
795
Sampa Misrab37be312019-07-03 02:26:41 -0500796 return response;
797}
798
799Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
800{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500801 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500802 auto response = internal::buildBIOSTables(request, payloadLength,
803 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
804
805 return response;
806}
807
808namespace bios
809{
810
811void registerHandlers()
812{
813 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
814 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
815}
816
817namespace internal
818{
819
820Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
821 const char* biosJsonDir, const char* biosTablePath)
822{
823 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
824 0);
825 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
826
John Wange96e7e52019-10-05 17:47:30 +0800827 if (setupConfig(biosJsonDir) != 0)
828 {
829 encode_get_bios_table_resp(
830 request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE,
831 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr,
832 response.size(), responsePtr);
833 return response;
834 }
835
Sampa Misrab37be312019-07-03 02:26:41 -0500836 uint32_t transferHandle{};
837 uint8_t transferOpFlag{};
838 uint8_t tableType{};
839
840 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
841 &transferOpFlag, &tableType);
842 if (rc == PLDM_SUCCESS)
843 {
844 BIOSTable BIOSStringTable(
845 ((std::string(biosTablePath) + "/stringTable")).c_str());
846 BIOSTable BIOSAttributeTable(
847 ((std::string(biosTablePath) + "/attributeTable")).c_str());
848 BIOSTable BIOSAttributeValueTable(
849 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
850 switch (tableType)
851 {
852 case PLDM_BIOS_STRING_TABLE:
853
John Wange96e7e52019-10-05 17:47:30 +0800854 response = getBIOSStringTable(BIOSStringTable, transferHandle,
855 transferOpFlag,
856 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500857 break;
858 case PLDM_BIOS_ATTR_TABLE:
859
860 if (BIOSStringTable.isEmpty())
861 {
862 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
863 }
864 else
865 {
866 response = getBIOSAttributeTable(
867 BIOSAttributeTable, BIOSStringTable, transferHandle,
868 transferOpFlag, request->hdr.instance_id, biosJsonDir);
869 }
870 break;
871 case PLDM_BIOS_ATTR_VAL_TABLE:
872 if (BIOSAttributeTable.isEmpty())
873 {
874 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
875 }
876 else
877 {
878 response = getBIOSAttributeValueTable(
879 BIOSAttributeValueTable, BIOSAttributeTable,
880 BIOSStringTable, transferHandle, transferOpFlag,
John Wang3ad21752019-10-06 16:42:21 +0800881 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500882 }
883 break;
884 default:
885 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
886 break;
887 }
888 }
889
890 if (rc != PLDM_SUCCESS)
891 {
892 uint32_t nxtTransferHandle{};
893 uint8_t transferFlag{};
894 size_t respPayloadLength{};
895
896 encode_get_bios_table_resp(request->hdr.instance_id, rc,
897 nxtTransferHandle, transferFlag, nullptr,
898 respPayloadLength, responsePtr);
899 }
900
901 return response;
902}
903
904} // end namespace internal
905} // namespace bios
906
Sampa Misra032bd502019-03-06 05:03:22 -0600907} // namespace responder
908} // namespace pldm