blob: 90d86c86ad9ef9816f3d7de723de7ea5981f42d5 [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>
11#include <iostream>
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
58} // namespace utils
59
Deepak Kodihalli3c275e12019-09-21 06:39:39 -050060Response getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -060061{
62 uint8_t seconds = 0;
63 uint8_t minutes = 0;
64 uint8_t hours = 0;
65 uint8_t day = 0;
66 uint8_t month = 0;
67 uint16_t year = 0;
68
69 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
70 constexpr auto bmcTimePath = "/xyz/openbmc_project/time/bmc";
vkaverapa6575b82019-04-03 05:33:52 -050071 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
72 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misra032bd502019-03-06 05:03:22 -060073 std::variant<EpochTimeUS> value;
74
75 auto bus = sdbusplus::bus::new_default();
76 try
77 {
78 auto service = getService(bus, bmcTimePath, timeInterface);
79
80 auto method = bus.new_method_call(service.c_str(), bmcTimePath,
81 dbusProperties, "Get");
82 method.append(timeInterface, "Elapsed");
83
84 auto reply = bus.call(method);
85 reply.read(value);
86 }
87
88 catch (std::exception& e)
89 {
90 log<level::ERR>("Error getting time", entry("PATH=%s", bmcTimePath),
91 entry("TIME INTERACE=%s", timeInterface));
92
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +053093 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
94 minutes, hours, day, month, year,
95 responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -050096 return response;
Sampa Misra032bd502019-03-06 05:03:22 -060097 }
98
99 uint64_t timeUsec = std::get<EpochTimeUS>(value);
100
101 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
102 std::chrono::microseconds(timeUsec))
103 .count();
104
105 utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
106
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530107 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
108 minutes, hours, day, month, year, responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500109 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600110}
111
Sampa Misrab37be312019-07-03 02:26:41 -0500112/** @brief Generate the next attribute handle
113 *
114 * @return - uint16_t - next attribute handle
115 */
116AttributeHandle nextAttributeHandle()
117{
118 static AttributeHandle attrHdl = 0;
119 return attrHdl++;
120}
121
122/** @brief Generate the next string handle
123 * *
124 * @return - uint16_t - next string handle
125 */
126StringHandle nextStringHandle()
127{
128 static StringHandle strHdl = 0;
129 return strHdl++;
130}
131
132/** @brief Construct the BIOS string table
133 *
134 * @param[in] BIOSStringTable - the string table
135 * @param[in] transferHandle - transfer handle to identify part of transfer
136 * @param[in] transferOpFlag - flag to indicate which part of data being
137 * transferred
138 * @param[in] instanceID - instance ID to identify the command
139 * @param[in] biosJsonDir - path where the BIOS json files are present
140 */
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500141Response getBIOSStringTable(BIOSTable& BIOSStringTable,
142 uint32_t /*transferHandle*/,
143 uint8_t /*transferOpFlag*/, uint8_t instanceID,
Sampa Misrab37be312019-07-03 02:26:41 -0500144 const char* biosJsonDir)
145{
146 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
147 0);
148 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
149
150 if (BIOSStringTable.isEmpty())
151 { // no persisted table, constructing fresh table and file
152 auto biosStrings = bios_parser::getStrings(biosJsonDir);
153 std::sort(biosStrings.begin(), biosStrings.end());
154 // remove all duplicate strings received from bios json
155 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
156 biosStrings.end());
157 size_t allStringsLen =
158 std::accumulate(biosStrings.begin(), biosStrings.end(), 0,
159 [](size_t sum, const std::string& elem) {
160 return sum + elem.size();
161 });
162 size_t sizeWithoutPad =
163 allStringsLen +
164 (biosStrings.size() * (sizeof(pldm_bios_string_table_entry) - 1));
165 uint8_t padSize = utils::getNumPadBytes(sizeWithoutPad);
166 uint32_t stringTableSize{};
167 uint32_t checkSum;
168 if (biosStrings.size())
169 {
170 stringTableSize = sizeWithoutPad + padSize + sizeof(checkSum);
171 }
172 Table stringTable(
173 stringTableSize,
174 0); // initializing to 0 so that pad will be automatically added
175 auto tablePtr = reinterpret_cast<uint8_t*>(stringTable.data());
176 for (const auto& elem : biosStrings)
177 {
178 auto stringPtr =
179 reinterpret_cast<struct pldm_bios_string_table_entry*>(
180 tablePtr);
181
182 stringPtr->string_handle = nextStringHandle();
183 stringPtr->string_length = elem.length();
184 memcpy(stringPtr->name, elem.c_str(), elem.length());
185 tablePtr += sizeof(stringPtr->string_handle) +
186 sizeof(stringPtr->string_length);
187 tablePtr += elem.length();
188 }
189 tablePtr += padSize;
190
191 if (stringTableSize)
192 {
193 // compute checksum
194 boost::crc_32_type result;
195 result.process_bytes(stringTable.data(), stringTableSize);
196 checkSum = result.checksum();
197 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
198 stringTable.data() + sizeWithoutPad + padSize);
199 BIOSStringTable.store(stringTable);
200 }
201
202 response.resize(sizeof(pldm_msg_hdr) +
203 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
204 stringTableSize,
205 0);
206 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
207 size_t respPayloadLength = response.size();
208 uint32_t nxtTransferHandle = 0;
209 uint8_t transferFlag = PLDM_START_AND_END;
210 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
211 transferFlag, stringTable.data(),
212 respPayloadLength, responsePtr);
213 }
214 else
215 { // persisted table present, constructing response
216 size_t respPayloadLength = response.size();
217 uint32_t nxtTransferHandle = 0;
218 uint8_t transferFlag = PLDM_START_AND_END;
219 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
220 transferFlag, nullptr, respPayloadLength,
221 responsePtr); // filling up the header here
222 BIOSStringTable.load(response);
223 }
224
225 return response;
226}
227
228/** @brief Find the string handle from the BIOS string table given the name
229 *
230 * @param[in] name - name of the BIOS string
231 * @param[in] BIOSStringTable - the string table
232 * @return - uint16_t - handle of the string
233 */
234StringHandle findStringHandle(const std::string& name,
235 const BIOSTable& BIOSStringTable)
236{
237 StringHandle hdl{};
238 Response response;
239 BIOSStringTable.load(response);
240
241 auto tableData = response.data();
242 size_t tableLen = response.size();
243 auto tableEntry =
244 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
245 while (1)
246 {
247 hdl = tableEntry->string_handle;
248 uint16_t len = tableEntry->string_length;
249 if (memcmp(name.c_str(), tableEntry->name, len) == 0)
250 {
251 break;
252 }
253 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
254
255 if (std::distance(tableData, response.data() + tableLen) <=
256 padChksumMax)
257 {
258 log<level::ERR>("Reached end of BIOS string table,did not find the "
259 "handle for the string",
260 entry("STRING=%s", name.c_str()));
261 elog<InternalFailure>();
262 break;
263 }
264
265 tableEntry =
266 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
267 }
268 return hdl;
269}
270
271/** @brief Find the string name from the BIOS string table for a string handle
272 *
273 * @param[in] stringHdl - string handle
274 * @param[in] BIOSStringTable - the string table
275 *
276 * @return - std::string - name of the corresponding BIOS string
277 */
278std::string findStringName(StringHandle stringHdl,
279 const BIOSTable& BIOSStringTable)
280{
281 std::string name;
282 Response response;
283 BIOSStringTable.load(response);
284
285 auto tableData = response.data();
286 size_t tableLen = response.size();
287 auto tableEntry =
288 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
289 while (1)
290 {
291 StringHandle currHdl = tableEntry->string_handle;
292 uint16_t len = tableEntry->string_length;
293 if (currHdl == stringHdl)
294 {
295 name.resize(len);
296 memcpy(name.data(), tableEntry->name, len);
297 break;
298 }
299 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
300
301 if (std::distance(tableData, response.data() + tableLen) <=
302 padChksumMax)
303 {
304 log<level::ERR>("Reached end of BIOS string table,did not find "
305 "string name for handle",
306 entry("STRING_HANDLE=%d", stringHdl));
307 break;
308 }
309
310 tableEntry =
311 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
312 }
313 return name;
314}
315
316namespace bios_type_enum
317{
318
Carol Wangdc220c82019-08-26 13:31:31 +0800319using namespace bios_parser::bios_enum;
320
Sampa Misrab37be312019-07-03 02:26:41 -0500321/** @brief Find the indices into the array of the possible values of string
322 * handles for the current values.This is used in attribute value table
323 *
324 * @param[in] possiVals - vector of string handles comprising all the possible
325 * values for an attribute
326 * @param[in] currVals - vector of strings comprising all current values
327 * for an attribute
328 * @param[in] BIOSStringTable - the string table
329 *
330 * @return - std::vector<uint8_t> - indices into the array of the possible
331 * values of string handles
332 */
333std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
334 CurrentValues currVals,
335 const BIOSTable& BIOSStringTable)
336{
337 std::vector<uint8_t> stringIndices;
338
339 for (const auto& currVal : currVals)
340 {
341 StringHandle curHdl;
342 try
343 {
344 curHdl = findStringHandle(currVal, BIOSStringTable);
345 }
346 catch (InternalFailure& e)
347 {
348 log<level::ERR>("Exception fetching handle for the string",
349 entry("STRING=%s", currVal.c_str()));
350 continue;
351 }
352
353 uint8_t i = 0;
354 for (auto possiHdl : possiVals)
355 {
356 if (possiHdl == curHdl)
357 {
358 stringIndices.push_back(i);
359 break;
360 }
361 i++;
362 }
363 }
364 return stringIndices;
365}
366
367/** @brief Find the indices into the array of the possible values of string
368 * handles for the default values. This is used in attribute table
369 *
370 * @param[in] possiVals - vector of strings comprising all the possible values
371 * for an attribute
372 * @param[in] defVals - vector of strings comprising all the default values
373 * for an attribute
374 * @return - std::vector<uint8_t> - indices into the array of the possible
375 * values of string
376 */
377std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
378 const DefaultValues& defVals)
379{
380 std::vector<uint8_t> defHdls;
381 for (const auto& defs : defVals)
382 {
383 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
384 if (index != possiVals.end())
385 {
386 defHdls.push_back(index - possiVals.begin());
387 }
388 }
389
390 return defHdls;
391}
392
393/** @brief Construct the attibute table for BIOS type Enumeration and
394 * Enumeration ReadOnly
395 * @param[in] BIOSStringTable - the string table
396 * @param[in] biosJsonDir - path where the BIOS json files are present
Carol Wangdc220c82019-08-26 13:31:31 +0800397 * @param[in,out] attributeTable - the attribute table
Sampa Misrab37be312019-07-03 02:26:41 -0500398 *
Sampa Misrab37be312019-07-03 02:26:41 -0500399 */
Carol Wangdc220c82019-08-26 13:31:31 +0800400void constructAttrTable(const BIOSTable& BIOSStringTable,
401 const char* biosJsonDir, Table& attributeTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500402{
403 setupValueLookup(biosJsonDir);
404 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
477/** @brief Construct the attibute value table for BIOS type Enumeration and
478 * Enumeration ReadOnly
479 *
480 * @param[in] BIOSAttributeTable - the attribute table
481 * @param[in] BIOSStringTable - the string table
482 *
483 * @return - Table - the attribute value table
484 */
485Table constructAttrValueTable(const BIOSTable& BIOSAttributeTable,
486 const BIOSTable& BIOSStringTable)
487{
488 Table attributeValueTable;
489 Response response;
490 BIOSAttributeTable.load(response);
491
492 auto tableData = response.data();
493 size_t tableLen = response.size();
494 auto attrPtr =
495 reinterpret_cast<struct pldm_bios_attr_table_entry*>(response.data());
496
497 while (1)
498 {
499 uint16_t attrHdl = attrPtr->attr_handle;
500 uint8_t attrType = attrPtr->attr_type;
501 uint16_t stringHdl = attrPtr->string_handle;
502 tableData += (sizeof(struct pldm_bios_attr_table_entry) - 1);
503 uint8_t numPossiVals = *tableData;
504 tableData++; // pass number of possible values
505 PossibleValuesByHandle possiValsByHdl(numPossiVals, 0);
506 memcpy(possiValsByHdl.data(), tableData,
507 sizeof(uint16_t) * numPossiVals);
508 tableData += sizeof(uint16_t) * numPossiVals;
509 uint8_t numDefVals = *tableData;
510 tableData++; // pass number of def vals
511 tableData += numDefVals; // pass all the def val indices
512
513 auto attrName = findStringName(stringHdl, BIOSStringTable);
514 if (attrName.empty())
515 {
516 if (std::distance(tableData, response.data() + tableLen) <=
517 padChksumMax)
518 {
519 log<level::ERR>("Did not find string name for handle",
520 entry("STRING_HANDLE=%d", stringHdl));
521 return attributeValueTable;
522 }
523 attrPtr =
524 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
525 continue;
526 }
527 CurrentValues currVals;
528 try
529 {
530 currVals = getAttrValue(attrName);
531 }
532 catch (const std::exception& e)
533 {
534 log<level::ERR>(
535 "constructAttrValueTable returned error for attribute",
536 entry("NAME=%s", attrName.c_str()),
537 entry("ERROR=%s", e.what()));
538 if (std::distance(tableData, response.data() + tableLen) <=
539 padChksumMax)
540 {
541 return attributeValueTable;
542 }
543
544 attrPtr =
545 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
546 continue;
547 }
548 // sorting since the possible values are stored in sorted way
549 std::sort(currVals.begin(), currVals.end());
550 auto currValStrIndices =
551 findStrIndices(possiValsByHdl, currVals, BIOSStringTable);
552 // number of current values equals to the number of string handles
553 // received not the number of strings received from getAttrValue
554 uint8_t numCurrVals = currValStrIndices.size();
555
556 BIOSTableRow enumAttrValTable(
557 (sizeof(struct pldm_bios_attr_val_table_entry) - 1) +
558 sizeof(uint8_t) + numCurrVals * sizeof(uint8_t),
559 0);
560 BIOSTableRow::iterator it = enumAttrValTable.begin();
561 auto attrValPtr =
562 reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
563 enumAttrValTable.data());
564 attrValPtr->attr_handle = attrHdl;
565 attrValPtr->attr_type = attrType;
566 std::advance(it, (sizeof(pldm_bios_attr_val_table_entry) - 1));
567 std::copy_n(&numCurrVals, sizeof(numCurrVals), it);
568 std::advance(it, sizeof(numCurrVals));
569 if (numCurrVals)
570 {
571 std::copy(currValStrIndices.begin(), currValStrIndices.end(), it);
572 std::advance(it, currValStrIndices.size());
573 }
574 std::move(enumAttrValTable.begin(), enumAttrValTable.end(),
575 std::back_inserter(attributeValueTable));
576
577 if (std::distance(tableData, response.data() + tableLen) <=
578 padChksumMax)
579 {
580 break;
581 }
582
583 attrPtr =
584 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
585 }
586
587 return attributeValueTable;
588}
589
590} // end namespace bios_type_enum
591
Carol Wangdc220c82019-08-26 13:31:31 +0800592namespace bios_type_string
593{
Carol Wang612f35b2019-08-26 17:14:26 +0800594
595using namespace bios_parser::bios_string;
596
Carol Wangdc220c82019-08-26 13:31:31 +0800597/** @brief Construct the attibute table for BIOS type String and
598 * String ReadOnly
599 * @param[in] BIOSStringTable - the string table
600 * @param[in] biosJsonDir - path where the BIOS json files are present
601 * @param[in,out] attributeTable - the attribute table
602 *
603 */
Carol Wang612f35b2019-08-26 17:14:26 +0800604void constructAttrTable(const BIOSTable& BIOSStringTable,
605 const char* biosJsonDir, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800606{
Carol Wang612f35b2019-08-26 17:14:26 +0800607 auto rc = setupValueLookup(biosJsonDir);
608 if (rc == -1)
609 {
610 log<level::ERR>("Failed to parse entries in Json file");
611 return;
612 }
613 const auto& attributeMap = getValues();
614 StringHandle strHandle;
615
616 for (const auto& [key, value] : attributeMap)
617 {
618 try
619 {
620 strHandle = findStringHandle(key, BIOSStringTable);
621 }
622 catch (InternalFailure& e)
623 {
624 log<level::ERR>("Could not find handle for BIOS string",
625 entry("ATTRIBUTE=%s", key.c_str()));
626 continue;
627 }
628
629 const auto& [type, strType, minStrLen, maxStrLen, defaultStrLen,
630 defaultStr] = value;
631 uint8_t typeOfAttr =
632 type ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
633
634 BIOSTableRow stringAttrTable(bios_parser::bios_string::attrTableSize +
635 defaultStr.size());
636 BIOSTableRow::iterator it = stringAttrTable.begin();
637 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
638 stringAttrTable.data());
639 attrPtr->attr_handle = nextAttributeHandle();
640 attrPtr->attr_type = typeOfAttr;
641 attrPtr->string_handle = strHandle;
642
643 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
644 std::copy_n(&strType, sizeof(uint8_t), it);
645 std::advance(it, sizeof(uint8_t));
646 std::copy_n(reinterpret_cast<const uint8_t*>(&minStrLen),
647 sizeof(uint16_t), it);
648 std::advance(it, sizeof(uint16_t));
649 std::copy_n(reinterpret_cast<const uint8_t*>(&maxStrLen),
650 sizeof(uint16_t), it);
651 std::advance(it, sizeof(uint16_t));
652 std::copy_n(reinterpret_cast<const uint8_t*>(&defaultStrLen),
653 sizeof(uint16_t), it);
654 std::advance(it, sizeof(uint16_t));
655 std::copy_n(defaultStr.data(), defaultStr.size(), it);
656 std::advance(it, defaultStr.size());
657
658 attributeTable.insert(attributeTable.end(), stringAttrTable.begin(),
659 stringAttrTable.end());
660 }
Carol Wangdc220c82019-08-26 13:31:31 +0800661}
662} // end namespace bios_type_string
663
664using typeHandler =
665 std::function<void(const BIOSTable& BIOSStringTable,
666 const char* biosJsonDir, Table& attributeTable)>;
667std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
668 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
669 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}};
670
Sampa Misrab37be312019-07-03 02:26:41 -0500671/** @brief Construct the BIOS attribute table
672 *
673 * @param[in] BIOSAttributeTable - the attribute table
674 * @param[in] BIOSStringTable - the string table
675 * @param[in] transferHandle - transfer handle to identify part of transfer
676 * @param[in] transferOpFlag - flag to indicate which part of data being
677 * transferred
678 * @param[in] instanceID - instance ID to identify the command
679 * @param[in] biosJsonDir - path where the BIOS json files are present
680 */
681Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
682 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500683 uint32_t /*transferHandle*/,
684 uint8_t /*transferOpFlag*/, uint8_t instanceID,
685 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500686{
687 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
688 0);
689 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
690 uint32_t nxtTransferHandle = 0;
691 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500692
693 if (BIOSAttributeTable.isEmpty())
694 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800695 Table attributeTable;
696 fs::path dir(biosJsonDir);
697
698 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
699 it++)
700 {
701 fs::path file = dir / it->first;
702 if (fs::exists(file))
703 {
704 it->second(BIOSStringTable, biosJsonDir, attributeTable);
705 }
706 }
707
708 if (attributeTable.empty())
709 { // no available json file is found
710 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
711 nxtTransferHandle, transferFlag, nullptr,
712 response.size(), responsePtr);
713 return response;
714 }
Sampa Misrab37be312019-07-03 02:26:41 -0500715
716 // calculate pad
717 uint8_t padSize = utils::getNumPadBytes(attributeTable.size());
718 std::vector<uint8_t> pad(padSize, 0);
719 if (padSize)
720 {
721 std::move(pad.begin(), pad.end(),
722 std::back_inserter(attributeTable));
723 }
724
725 if (!attributeTable.empty())
726 {
727 // compute checksum
728 boost::crc_32_type result;
729 size_t size = attributeTable.size();
730 result.process_bytes(attributeTable.data(), size);
731 uint32_t checkSum = result.checksum();
732 attributeTable.resize(size + sizeof(checkSum));
733 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
734 attributeTable.data() + size);
735 BIOSAttributeTable.store(attributeTable);
736 }
737 response.resize(sizeof(pldm_msg_hdr) +
738 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
739 attributeTable.size());
740 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500741 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
742 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800743 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500744 }
745 else
746 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500747 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800748 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500749 responsePtr); // filling up the header here
750 BIOSAttributeTable.load(response);
751 }
752
753 return response;
754}
755
756/** @brief Construct the BIOS attribute value table
757 *
758 * @param[in] BIOSAttributeValueTable - the attribute value table
759 * @param[in] BIOSAttributeTable - the attribute table
760 * @param[in] BIOSStringTable - the string table
761 * @param[in] transferHandle - transfer handle to identify part of transfer
762 * @param[in] transferOpFlag - flag to indicate which part of data being
763 * transferred
764 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500765 */
766Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
767 const BIOSTable& BIOSAttributeTable,
768 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500769 uint32_t& /*transferHandle*/,
770 uint8_t& /*transferOpFlag*/,
771 uint8_t instanceID,
772 const char* /*biosJsonDir*/)
Sampa Misrab37be312019-07-03 02:26:41 -0500773{
774 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
775 0);
776 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
777 uint32_t nxtTransferHandle = 0;
778 uint8_t transferFlag = PLDM_START_AND_END;
779 size_t respPayloadLength{};
780
781 if (BIOSAttributeValueTable.isEmpty())
782 { // no persisted table, constructing fresh table and data
783 Table attributeValueTable = bios_type_enum::constructAttrValueTable(
784 BIOSAttributeTable, BIOSStringTable);
785 // calculate pad
786 uint8_t padSize = utils::getNumPadBytes(attributeValueTable.size());
787 std::vector<uint8_t> pad(padSize, 0);
788 if (padSize)
789 {
790 std::move(pad.begin(), pad.end(),
791 std::back_inserter(attributeValueTable));
792 }
793 if (!attributeValueTable.empty())
794 {
795 // compute checksum
796 boost::crc_32_type result;
797 result.process_bytes(attributeValueTable.data(),
798 attributeValueTable.size());
799 uint32_t checkSum = result.checksum();
800 size_t size = attributeValueTable.size();
801 attributeValueTable.resize(size + sizeof(checkSum));
802 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
803 attributeValueTable.data() + size);
804 BIOSAttributeValueTable.store(attributeValueTable);
805 }
806
807 response.resize(sizeof(pldm_msg_hdr) +
808 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
809 attributeValueTable.size());
810 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
811 respPayloadLength = response.size();
812 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
813 transferFlag, attributeValueTable.data(),
814 respPayloadLength, responsePtr);
815 }
816 else
817 { // persisted table present, constructing response
818 respPayloadLength = response.size();
819 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
820 transferFlag, nullptr, respPayloadLength,
821 responsePtr); // filling up the header here
822 BIOSAttributeValueTable.load(response);
823 }
824
825 return response;
826}
827
828Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
829{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500830 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500831 auto response = internal::buildBIOSTables(request, payloadLength,
832 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
833
834 return response;
835}
836
837namespace bios
838{
839
840void registerHandlers()
841{
842 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
843 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
844}
845
846namespace internal
847{
848
849Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
850 const char* biosJsonDir, const char* biosTablePath)
851{
852 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
853 0);
854 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
855
856 uint32_t transferHandle{};
857 uint8_t transferOpFlag{};
858 uint8_t tableType{};
859
860 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
861 &transferOpFlag, &tableType);
862 if (rc == PLDM_SUCCESS)
863 {
864 BIOSTable BIOSStringTable(
865 ((std::string(biosTablePath) + "/stringTable")).c_str());
866 BIOSTable BIOSAttributeTable(
867 ((std::string(biosTablePath) + "/attributeTable")).c_str());
868 BIOSTable BIOSAttributeValueTable(
869 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
870 switch (tableType)
871 {
872 case PLDM_BIOS_STRING_TABLE:
873
874 response = getBIOSStringTable(
875 BIOSStringTable, transferHandle, transferOpFlag,
876 request->hdr.instance_id, biosJsonDir);
877 break;
878 case PLDM_BIOS_ATTR_TABLE:
879
880 if (BIOSStringTable.isEmpty())
881 {
882 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
883 }
884 else
885 {
886 response = getBIOSAttributeTable(
887 BIOSAttributeTable, BIOSStringTable, transferHandle,
888 transferOpFlag, request->hdr.instance_id, biosJsonDir);
889 }
890 break;
891 case PLDM_BIOS_ATTR_VAL_TABLE:
892 if (BIOSAttributeTable.isEmpty())
893 {
894 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
895 }
896 else
897 {
898 response = getBIOSAttributeValueTable(
899 BIOSAttributeValueTable, BIOSAttributeTable,
900 BIOSStringTable, transferHandle, transferOpFlag,
901 request->hdr.instance_id, biosJsonDir);
902 }
903 break;
904 default:
905 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
906 break;
907 }
908 }
909
910 if (rc != PLDM_SUCCESS)
911 {
912 uint32_t nxtTransferHandle{};
913 uint8_t transferFlag{};
914 size_t respPayloadLength{};
915
916 encode_get_bios_table_resp(request->hdr.instance_id, rc,
917 nxtTransferHandle, transferFlag, nullptr,
918 respPayloadLength, responsePtr);
919 }
920
921 return response;
922}
923
924} // end namespace internal
925} // namespace bios
926
Sampa Misra032bd502019-03-06 05:03:22 -0600927} // namespace responder
928} // namespace pldm