blob: 392f58a2a976ea34f73f390a0313914bf8506f15 [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;
22using namespace bios_parser::bios_enum;
23
Sampa Misra032bd502019-03-06 05:03:22 -060024namespace pldm
25{
26
27using namespace phosphor::logging;
Sampa Misrab37be312019-07-03 02:26:41 -050028using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Sampa Misra032bd502019-03-06 05:03:22 -060029using EpochTimeUS = uint64_t;
Sampa Misrab37be312019-07-03 02:26:41 -050030using BIOSTableRow = std::vector<uint8_t>;
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
Jinu Joy Thomasf666db12019-05-29 05:22:31 -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 */
141Response getBIOSStringTable(BIOSTable& BIOSStringTable, uint32_t transferHandle,
142 uint8_t transferOpFlag, uint8_t instanceID,
143 const char* biosJsonDir)
144{
145 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
146 0);
147 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
148
149 if (BIOSStringTable.isEmpty())
150 { // no persisted table, constructing fresh table and file
151 auto biosStrings = bios_parser::getStrings(biosJsonDir);
152 std::sort(biosStrings.begin(), biosStrings.end());
153 // remove all duplicate strings received from bios json
154 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
155 biosStrings.end());
156 size_t allStringsLen =
157 std::accumulate(biosStrings.begin(), biosStrings.end(), 0,
158 [](size_t sum, const std::string& elem) {
159 return sum + elem.size();
160 });
161 size_t sizeWithoutPad =
162 allStringsLen +
163 (biosStrings.size() * (sizeof(pldm_bios_string_table_entry) - 1));
164 uint8_t padSize = utils::getNumPadBytes(sizeWithoutPad);
165 uint32_t stringTableSize{};
166 uint32_t checkSum;
167 if (biosStrings.size())
168 {
169 stringTableSize = sizeWithoutPad + padSize + sizeof(checkSum);
170 }
171 Table stringTable(
172 stringTableSize,
173 0); // initializing to 0 so that pad will be automatically added
174 auto tablePtr = reinterpret_cast<uint8_t*>(stringTable.data());
175 for (const auto& elem : biosStrings)
176 {
177 auto stringPtr =
178 reinterpret_cast<struct pldm_bios_string_table_entry*>(
179 tablePtr);
180
181 stringPtr->string_handle = nextStringHandle();
182 stringPtr->string_length = elem.length();
183 memcpy(stringPtr->name, elem.c_str(), elem.length());
184 tablePtr += sizeof(stringPtr->string_handle) +
185 sizeof(stringPtr->string_length);
186 tablePtr += elem.length();
187 }
188 tablePtr += padSize;
189
190 if (stringTableSize)
191 {
192 // compute checksum
193 boost::crc_32_type result;
194 result.process_bytes(stringTable.data(), stringTableSize);
195 checkSum = result.checksum();
196 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
197 stringTable.data() + sizeWithoutPad + padSize);
198 BIOSStringTable.store(stringTable);
199 }
200
201 response.resize(sizeof(pldm_msg_hdr) +
202 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
203 stringTableSize,
204 0);
205 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
206 size_t respPayloadLength = response.size();
207 uint32_t nxtTransferHandle = 0;
208 uint8_t transferFlag = PLDM_START_AND_END;
209 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
210 transferFlag, stringTable.data(),
211 respPayloadLength, responsePtr);
212 }
213 else
214 { // persisted table present, constructing response
215 size_t respPayloadLength = response.size();
216 uint32_t nxtTransferHandle = 0;
217 uint8_t transferFlag = PLDM_START_AND_END;
218 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
219 transferFlag, nullptr, respPayloadLength,
220 responsePtr); // filling up the header here
221 BIOSStringTable.load(response);
222 }
223
224 return response;
225}
226
227/** @brief Find the string handle from the BIOS string table given the name
228 *
229 * @param[in] name - name of the BIOS string
230 * @param[in] BIOSStringTable - the string table
231 * @return - uint16_t - handle of the string
232 */
233StringHandle findStringHandle(const std::string& name,
234 const BIOSTable& BIOSStringTable)
235{
236 StringHandle hdl{};
237 Response response;
238 BIOSStringTable.load(response);
239
240 auto tableData = response.data();
241 size_t tableLen = response.size();
242 auto tableEntry =
243 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
244 while (1)
245 {
246 hdl = tableEntry->string_handle;
247 uint16_t len = tableEntry->string_length;
248 if (memcmp(name.c_str(), tableEntry->name, len) == 0)
249 {
250 break;
251 }
252 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
253
254 if (std::distance(tableData, response.data() + tableLen) <=
255 padChksumMax)
256 {
257 log<level::ERR>("Reached end of BIOS string table,did not find the "
258 "handle for the string",
259 entry("STRING=%s", name.c_str()));
260 elog<InternalFailure>();
261 break;
262 }
263
264 tableEntry =
265 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
266 }
267 return hdl;
268}
269
270/** @brief Find the string name from the BIOS string table for a string handle
271 *
272 * @param[in] stringHdl - string handle
273 * @param[in] BIOSStringTable - the string table
274 *
275 * @return - std::string - name of the corresponding BIOS string
276 */
277std::string findStringName(StringHandle stringHdl,
278 const BIOSTable& BIOSStringTable)
279{
280 std::string name;
281 Response response;
282 BIOSStringTable.load(response);
283
284 auto tableData = response.data();
285 size_t tableLen = response.size();
286 auto tableEntry =
287 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
288 while (1)
289 {
290 StringHandle currHdl = tableEntry->string_handle;
291 uint16_t len = tableEntry->string_length;
292 if (currHdl == stringHdl)
293 {
294 name.resize(len);
295 memcpy(name.data(), tableEntry->name, len);
296 break;
297 }
298 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
299
300 if (std::distance(tableData, response.data() + tableLen) <=
301 padChksumMax)
302 {
303 log<level::ERR>("Reached end of BIOS string table,did not find "
304 "string name for handle",
305 entry("STRING_HANDLE=%d", stringHdl));
306 break;
307 }
308
309 tableEntry =
310 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
311 }
312 return name;
313}
314
315namespace bios_type_enum
316{
317
318/** @brief Find the indices into the array of the possible values of string
319 * handles for the current values.This is used in attribute value table
320 *
321 * @param[in] possiVals - vector of string handles comprising all the possible
322 * values for an attribute
323 * @param[in] currVals - vector of strings comprising all current values
324 * for an attribute
325 * @param[in] BIOSStringTable - the string table
326 *
327 * @return - std::vector<uint8_t> - indices into the array of the possible
328 * values of string handles
329 */
330std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
331 CurrentValues currVals,
332 const BIOSTable& BIOSStringTable)
333{
334 std::vector<uint8_t> stringIndices;
335
336 for (const auto& currVal : currVals)
337 {
338 StringHandle curHdl;
339 try
340 {
341 curHdl = findStringHandle(currVal, BIOSStringTable);
342 }
343 catch (InternalFailure& e)
344 {
345 log<level::ERR>("Exception fetching handle for the string",
346 entry("STRING=%s", currVal.c_str()));
347 continue;
348 }
349
350 uint8_t i = 0;
351 for (auto possiHdl : possiVals)
352 {
353 if (possiHdl == curHdl)
354 {
355 stringIndices.push_back(i);
356 break;
357 }
358 i++;
359 }
360 }
361 return stringIndices;
362}
363
364/** @brief Find the indices into the array of the possible values of string
365 * handles for the default values. This is used in attribute table
366 *
367 * @param[in] possiVals - vector of strings comprising all the possible values
368 * for an attribute
369 * @param[in] defVals - vector of strings comprising all the default values
370 * for an attribute
371 * @return - std::vector<uint8_t> - indices into the array of the possible
372 * values of string
373 */
374std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
375 const DefaultValues& defVals)
376{
377 std::vector<uint8_t> defHdls;
378 for (const auto& defs : defVals)
379 {
380 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
381 if (index != possiVals.end())
382 {
383 defHdls.push_back(index - possiVals.begin());
384 }
385 }
386
387 return defHdls;
388}
389
390/** @brief Construct the attibute table for BIOS type Enumeration and
391 * Enumeration ReadOnly
392 * @param[in] BIOSStringTable - the string table
393 * @param[in] biosJsonDir - path where the BIOS json files are present
394 *
395 * @return - Table - the attribute eenumeration table
396 */
397Table constructAttrTable(const BIOSTable& BIOSStringTable,
398 const char* biosJsonDir)
399{
400 setupValueLookup(biosJsonDir);
401 const auto& attributeMap = getValues();
402 Table attributeTable;
403 StringHandle strHandle;
404
405 for (const auto& [key, value] : attributeMap)
406 {
407 try
408 {
409 strHandle = findStringHandle(key, BIOSStringTable);
410 }
411 catch (InternalFailure& e)
412 {
413 log<level::ERR>("Could not find handle for BIOS string",
414 entry("ATTRIBUTE=%s", key.c_str()));
415 continue;
416 }
417 uint8_t typeOfAttr = (std::get<0>(value))
418 ? PLDM_BIOS_ENUMERATION_READ_ONLY
419 : PLDM_BIOS_ENUMERATION;
420 PossibleValues possiVals = std::get<1>(value);
421 DefaultValues defVals = std::get<2>(value);
422 // both the possible and default values are stored in sorted manner to
423 // ease in fetching back/comparison
424 std::sort(possiVals.begin(), possiVals.end());
425 std::sort(defVals.begin(), defVals.end());
426
427 std::vector<StringHandle> possiValsByHdl;
428 for (const auto& elem : possiVals)
429 {
430 try
431 {
432 auto hdl = findStringHandle(elem, BIOSStringTable);
433 possiValsByHdl.push_back(std::move(hdl));
434 }
435 catch (InternalFailure& e)
436 {
437 log<level::ERR>("Could not find handle for BIOS string",
438 entry("STRING=%s", elem.c_str()));
439 continue;
440 }
441 }
442 auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
443
444 BIOSTableRow enumAttrTable(
445 (sizeof(struct pldm_bios_attr_table_entry) - 1) + sizeof(uint8_t) +
446 possiValsByHdl.size() * sizeof(uint16_t) + sizeof(uint8_t) +
447 defValsByHdl.size() * sizeof(uint8_t),
448 0);
449 BIOSTableRow::iterator it = enumAttrTable.begin();
450 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
451 enumAttrTable.data());
452 attrPtr->attr_handle = nextAttributeHandle();
453 attrPtr->attr_type = typeOfAttr;
454 attrPtr->string_handle = std::move(strHandle);
455 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
456 uint8_t numPossibleVals = possiValsByHdl.size();
457 std::copy_n(&numPossibleVals, sizeof(numPossibleVals), it);
458 std::advance(it, sizeof(numPossibleVals));
459 std::copy_n(reinterpret_cast<uint8_t*>(possiValsByHdl.data()),
460 sizeof(uint16_t) * possiValsByHdl.size(), it);
461 std::advance(
462 it, sizeof(uint16_t) *
463 possiValsByHdl.size()); // possible val handle is uint16_t
464 uint8_t numDefaultVals = defValsByHdl.size();
465 std::copy_n(&numDefaultVals, sizeof(numDefaultVals), it);
466 std::advance(it, sizeof(numDefaultVals));
467 std::copy(defValsByHdl.begin(), defValsByHdl.end(), it);
468 std::advance(it, defValsByHdl.size());
469
470 std::move(enumAttrTable.begin(), enumAttrTable.end(),
471 std::back_inserter(attributeTable));
472 }
473
474 return attributeTable;
475}
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
592/** @brief Construct the BIOS attribute table
593 *
594 * @param[in] BIOSAttributeTable - the attribute table
595 * @param[in] BIOSStringTable - the string table
596 * @param[in] transferHandle - transfer handle to identify part of transfer
597 * @param[in] transferOpFlag - flag to indicate which part of data being
598 * transferred
599 * @param[in] instanceID - instance ID to identify the command
600 * @param[in] biosJsonDir - path where the BIOS json files are present
601 */
602Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
603 const BIOSTable& BIOSStringTable,
604 uint32_t transferHandle, uint8_t transferOpFlag,
605 uint8_t instanceID, const char* biosJsonDir)
606{
607 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
608 0);
609 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
610 uint32_t nxtTransferHandle = 0;
611 uint8_t transferFlag = PLDM_START_AND_END;
612 size_t respPayloadLength{};
613
614 if (BIOSAttributeTable.isEmpty())
615 { // no persisted table, constructing fresh table and response
616 auto attributeTable =
617 bios_type_enum::constructAttrTable(BIOSStringTable, biosJsonDir);
618
619 // calculate pad
620 uint8_t padSize = utils::getNumPadBytes(attributeTable.size());
621 std::vector<uint8_t> pad(padSize, 0);
622 if (padSize)
623 {
624 std::move(pad.begin(), pad.end(),
625 std::back_inserter(attributeTable));
626 }
627
628 if (!attributeTable.empty())
629 {
630 // compute checksum
631 boost::crc_32_type result;
632 size_t size = attributeTable.size();
633 result.process_bytes(attributeTable.data(), size);
634 uint32_t checkSum = result.checksum();
635 attributeTable.resize(size + sizeof(checkSum));
636 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
637 attributeTable.data() + size);
638 BIOSAttributeTable.store(attributeTable);
639 }
640 response.resize(sizeof(pldm_msg_hdr) +
641 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
642 attributeTable.size());
643 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
644 respPayloadLength = response.size();
645 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
646 transferFlag, attributeTable.data(),
647 respPayloadLength, responsePtr);
648 }
649 else
650 { // persisted table present, constructing response
651 respPayloadLength = response.size();
652 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
653 transferFlag, nullptr, respPayloadLength,
654 responsePtr); // filling up the header here
655 BIOSAttributeTable.load(response);
656 }
657
658 return response;
659}
660
661/** @brief Construct the BIOS attribute value table
662 *
663 * @param[in] BIOSAttributeValueTable - the attribute value table
664 * @param[in] BIOSAttributeTable - the attribute table
665 * @param[in] BIOSStringTable - the string table
666 * @param[in] transferHandle - transfer handle to identify part of transfer
667 * @param[in] transferOpFlag - flag to indicate which part of data being
668 * transferred
669 * @param[in] instanceID - instance ID to identify the command
670 * @param[in] biosJsonDir - path where the BIOS json files are present
671 */
672Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
673 const BIOSTable& BIOSAttributeTable,
674 const BIOSTable& BIOSStringTable,
675 uint32_t& transferHandle,
676 uint8_t& transferOpFlag, uint8_t instanceID,
677 const char* biosJsonDir)
678{
679 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
680 0);
681 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
682 uint32_t nxtTransferHandle = 0;
683 uint8_t transferFlag = PLDM_START_AND_END;
684 size_t respPayloadLength{};
685
686 if (BIOSAttributeValueTable.isEmpty())
687 { // no persisted table, constructing fresh table and data
688 Table attributeValueTable = bios_type_enum::constructAttrValueTable(
689 BIOSAttributeTable, BIOSStringTable);
690 // calculate pad
691 uint8_t padSize = utils::getNumPadBytes(attributeValueTable.size());
692 std::vector<uint8_t> pad(padSize, 0);
693 if (padSize)
694 {
695 std::move(pad.begin(), pad.end(),
696 std::back_inserter(attributeValueTable));
697 }
698 if (!attributeValueTable.empty())
699 {
700 // compute checksum
701 boost::crc_32_type result;
702 result.process_bytes(attributeValueTable.data(),
703 attributeValueTable.size());
704 uint32_t checkSum = result.checksum();
705 size_t size = attributeValueTable.size();
706 attributeValueTable.resize(size + sizeof(checkSum));
707 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
708 attributeValueTable.data() + size);
709 BIOSAttributeValueTable.store(attributeValueTable);
710 }
711
712 response.resize(sizeof(pldm_msg_hdr) +
713 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
714 attributeValueTable.size());
715 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
716 respPayloadLength = response.size();
717 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
718 transferFlag, attributeValueTable.data(),
719 respPayloadLength, responsePtr);
720 }
721 else
722 { // persisted table present, constructing response
723 respPayloadLength = response.size();
724 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
725 transferFlag, nullptr, respPayloadLength,
726 responsePtr); // filling up the header here
727 BIOSAttributeValueTable.load(response);
728 }
729
730 return response;
731}
732
733Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
734{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500735 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500736 auto response = internal::buildBIOSTables(request, payloadLength,
737 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
738
739 return response;
740}
741
742namespace bios
743{
744
745void registerHandlers()
746{
747 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
748 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
749}
750
751namespace internal
752{
753
754Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
755 const char* biosJsonDir, const char* biosTablePath)
756{
757 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
758 0);
759 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
760
761 uint32_t transferHandle{};
762 uint8_t transferOpFlag{};
763 uint8_t tableType{};
764
765 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
766 &transferOpFlag, &tableType);
767 if (rc == PLDM_SUCCESS)
768 {
769 BIOSTable BIOSStringTable(
770 ((std::string(biosTablePath) + "/stringTable")).c_str());
771 BIOSTable BIOSAttributeTable(
772 ((std::string(biosTablePath) + "/attributeTable")).c_str());
773 BIOSTable BIOSAttributeValueTable(
774 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
775 switch (tableType)
776 {
777 case PLDM_BIOS_STRING_TABLE:
778
779 response = getBIOSStringTable(
780 BIOSStringTable, transferHandle, transferOpFlag,
781 request->hdr.instance_id, biosJsonDir);
782 break;
783 case PLDM_BIOS_ATTR_TABLE:
784
785 if (BIOSStringTable.isEmpty())
786 {
787 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
788 }
789 else
790 {
791 response = getBIOSAttributeTable(
792 BIOSAttributeTable, BIOSStringTable, transferHandle,
793 transferOpFlag, request->hdr.instance_id, biosJsonDir);
794 }
795 break;
796 case PLDM_BIOS_ATTR_VAL_TABLE:
797 if (BIOSAttributeTable.isEmpty())
798 {
799 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
800 }
801 else
802 {
803 response = getBIOSAttributeValueTable(
804 BIOSAttributeValueTable, BIOSAttributeTable,
805 BIOSStringTable, transferHandle, transferOpFlag,
806 request->hdr.instance_id, biosJsonDir);
807 }
808 break;
809 default:
810 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
811 break;
812 }
813 }
814
815 if (rc != PLDM_SUCCESS)
816 {
817 uint32_t nxtTransferHandle{};
818 uint8_t transferFlag{};
819 size_t respPayloadLength{};
820
821 encode_get_bios_table_resp(request->hdr.instance_id, rc,
822 nxtTransferHandle, transferFlag, nullptr,
823 respPayloadLength, responsePtr);
824 }
825
826 return response;
827}
828
829} // end namespace internal
830} // namespace bios
831
Sampa Misra032bd502019-03-06 05:03:22 -0600832} // namespace responder
833} // namespace pldm