blob: c88a25cd8a73e4ae308de5a4fe145ad4e426eee1 [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
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
319/** @brief Find the indices into the array of the possible values of string
320 * handles for the current values.This is used in attribute value table
321 *
322 * @param[in] possiVals - vector of string handles comprising all the possible
323 * values for an attribute
324 * @param[in] currVals - vector of strings comprising all current values
325 * for an attribute
326 * @param[in] BIOSStringTable - the string table
327 *
328 * @return - std::vector<uint8_t> - indices into the array of the possible
329 * values of string handles
330 */
331std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
332 CurrentValues currVals,
333 const BIOSTable& BIOSStringTable)
334{
335 std::vector<uint8_t> stringIndices;
336
337 for (const auto& currVal : currVals)
338 {
339 StringHandle curHdl;
340 try
341 {
342 curHdl = findStringHandle(currVal, BIOSStringTable);
343 }
344 catch (InternalFailure& e)
345 {
346 log<level::ERR>("Exception fetching handle for the string",
347 entry("STRING=%s", currVal.c_str()));
348 continue;
349 }
350
351 uint8_t i = 0;
352 for (auto possiHdl : possiVals)
353 {
354 if (possiHdl == curHdl)
355 {
356 stringIndices.push_back(i);
357 break;
358 }
359 i++;
360 }
361 }
362 return stringIndices;
363}
364
365/** @brief Find the indices into the array of the possible values of string
366 * handles for the default values. This is used in attribute table
367 *
368 * @param[in] possiVals - vector of strings comprising all the possible values
369 * for an attribute
370 * @param[in] defVals - vector of strings comprising all the default values
371 * for an attribute
372 * @return - std::vector<uint8_t> - indices into the array of the possible
373 * values of string
374 */
375std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
376 const DefaultValues& defVals)
377{
378 std::vector<uint8_t> defHdls;
379 for (const auto& defs : defVals)
380 {
381 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
382 if (index != possiVals.end())
383 {
384 defHdls.push_back(index - possiVals.begin());
385 }
386 }
387
388 return defHdls;
389}
390
391/** @brief Construct the attibute table for BIOS type Enumeration and
392 * Enumeration ReadOnly
393 * @param[in] BIOSStringTable - the string table
394 * @param[in] biosJsonDir - path where the BIOS json files are present
395 *
396 * @return - Table - the attribute eenumeration table
397 */
398Table constructAttrTable(const BIOSTable& BIOSStringTable,
399 const char* biosJsonDir)
400{
401 setupValueLookup(biosJsonDir);
402 const auto& attributeMap = getValues();
403 Table attributeTable;
404 StringHandle strHandle;
405
406 for (const auto& [key, value] : attributeMap)
407 {
408 try
409 {
410 strHandle = findStringHandle(key, BIOSStringTable);
411 }
412 catch (InternalFailure& e)
413 {
414 log<level::ERR>("Could not find handle for BIOS string",
415 entry("ATTRIBUTE=%s", key.c_str()));
416 continue;
417 }
418 uint8_t typeOfAttr = (std::get<0>(value))
419 ? PLDM_BIOS_ENUMERATION_READ_ONLY
420 : PLDM_BIOS_ENUMERATION;
421 PossibleValues possiVals = std::get<1>(value);
422 DefaultValues defVals = std::get<2>(value);
423 // both the possible and default values are stored in sorted manner to
424 // ease in fetching back/comparison
425 std::sort(possiVals.begin(), possiVals.end());
426 std::sort(defVals.begin(), defVals.end());
427
428 std::vector<StringHandle> possiValsByHdl;
429 for (const auto& elem : possiVals)
430 {
431 try
432 {
433 auto hdl = findStringHandle(elem, BIOSStringTable);
434 possiValsByHdl.push_back(std::move(hdl));
435 }
436 catch (InternalFailure& e)
437 {
438 log<level::ERR>("Could not find handle for BIOS string",
439 entry("STRING=%s", elem.c_str()));
440 continue;
441 }
442 }
443 auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
444
445 BIOSTableRow enumAttrTable(
446 (sizeof(struct pldm_bios_attr_table_entry) - 1) + sizeof(uint8_t) +
447 possiValsByHdl.size() * sizeof(uint16_t) + sizeof(uint8_t) +
448 defValsByHdl.size() * sizeof(uint8_t),
449 0);
450 BIOSTableRow::iterator it = enumAttrTable.begin();
451 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
452 enumAttrTable.data());
453 attrPtr->attr_handle = nextAttributeHandle();
454 attrPtr->attr_type = typeOfAttr;
455 attrPtr->string_handle = std::move(strHandle);
456 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
457 uint8_t numPossibleVals = possiValsByHdl.size();
458 std::copy_n(&numPossibleVals, sizeof(numPossibleVals), it);
459 std::advance(it, sizeof(numPossibleVals));
460 std::copy_n(reinterpret_cast<uint8_t*>(possiValsByHdl.data()),
461 sizeof(uint16_t) * possiValsByHdl.size(), it);
462 std::advance(
463 it, sizeof(uint16_t) *
464 possiValsByHdl.size()); // possible val handle is uint16_t
465 uint8_t numDefaultVals = defValsByHdl.size();
466 std::copy_n(&numDefaultVals, sizeof(numDefaultVals), it);
467 std::advance(it, sizeof(numDefaultVals));
468 std::copy(defValsByHdl.begin(), defValsByHdl.end(), it);
469 std::advance(it, defValsByHdl.size());
470
471 std::move(enumAttrTable.begin(), enumAttrTable.end(),
472 std::back_inserter(attributeTable));
473 }
474
475 return attributeTable;
476}
477
478/** @brief Construct the attibute value table for BIOS type Enumeration and
479 * Enumeration ReadOnly
480 *
481 * @param[in] BIOSAttributeTable - the attribute table
482 * @param[in] BIOSStringTable - the string table
483 *
484 * @return - Table - the attribute value table
485 */
486Table constructAttrValueTable(const BIOSTable& BIOSAttributeTable,
487 const BIOSTable& BIOSStringTable)
488{
489 Table attributeValueTable;
490 Response response;
491 BIOSAttributeTable.load(response);
492
493 auto tableData = response.data();
494 size_t tableLen = response.size();
495 auto attrPtr =
496 reinterpret_cast<struct pldm_bios_attr_table_entry*>(response.data());
497
498 while (1)
499 {
500 uint16_t attrHdl = attrPtr->attr_handle;
501 uint8_t attrType = attrPtr->attr_type;
502 uint16_t stringHdl = attrPtr->string_handle;
503 tableData += (sizeof(struct pldm_bios_attr_table_entry) - 1);
504 uint8_t numPossiVals = *tableData;
505 tableData++; // pass number of possible values
506 PossibleValuesByHandle possiValsByHdl(numPossiVals, 0);
507 memcpy(possiValsByHdl.data(), tableData,
508 sizeof(uint16_t) * numPossiVals);
509 tableData += sizeof(uint16_t) * numPossiVals;
510 uint8_t numDefVals = *tableData;
511 tableData++; // pass number of def vals
512 tableData += numDefVals; // pass all the def val indices
513
514 auto attrName = findStringName(stringHdl, BIOSStringTable);
515 if (attrName.empty())
516 {
517 if (std::distance(tableData, response.data() + tableLen) <=
518 padChksumMax)
519 {
520 log<level::ERR>("Did not find string name for handle",
521 entry("STRING_HANDLE=%d", stringHdl));
522 return attributeValueTable;
523 }
524 attrPtr =
525 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
526 continue;
527 }
528 CurrentValues currVals;
529 try
530 {
531 currVals = getAttrValue(attrName);
532 }
533 catch (const std::exception& e)
534 {
535 log<level::ERR>(
536 "constructAttrValueTable returned error for attribute",
537 entry("NAME=%s", attrName.c_str()),
538 entry("ERROR=%s", e.what()));
539 if (std::distance(tableData, response.data() + tableLen) <=
540 padChksumMax)
541 {
542 return attributeValueTable;
543 }
544
545 attrPtr =
546 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
547 continue;
548 }
549 // sorting since the possible values are stored in sorted way
550 std::sort(currVals.begin(), currVals.end());
551 auto currValStrIndices =
552 findStrIndices(possiValsByHdl, currVals, BIOSStringTable);
553 // number of current values equals to the number of string handles
554 // received not the number of strings received from getAttrValue
555 uint8_t numCurrVals = currValStrIndices.size();
556
557 BIOSTableRow enumAttrValTable(
558 (sizeof(struct pldm_bios_attr_val_table_entry) - 1) +
559 sizeof(uint8_t) + numCurrVals * sizeof(uint8_t),
560 0);
561 BIOSTableRow::iterator it = enumAttrValTable.begin();
562 auto attrValPtr =
563 reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
564 enumAttrValTable.data());
565 attrValPtr->attr_handle = attrHdl;
566 attrValPtr->attr_type = attrType;
567 std::advance(it, (sizeof(pldm_bios_attr_val_table_entry) - 1));
568 std::copy_n(&numCurrVals, sizeof(numCurrVals), it);
569 std::advance(it, sizeof(numCurrVals));
570 if (numCurrVals)
571 {
572 std::copy(currValStrIndices.begin(), currValStrIndices.end(), it);
573 std::advance(it, currValStrIndices.size());
574 }
575 std::move(enumAttrValTable.begin(), enumAttrValTable.end(),
576 std::back_inserter(attributeValueTable));
577
578 if (std::distance(tableData, response.data() + tableLen) <=
579 padChksumMax)
580 {
581 break;
582 }
583
584 attrPtr =
585 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
586 }
587
588 return attributeValueTable;
589}
590
591} // end namespace bios_type_enum
592
593/** @brief Construct the BIOS attribute table
594 *
595 * @param[in] BIOSAttributeTable - the attribute table
596 * @param[in] BIOSStringTable - the string table
597 * @param[in] transferHandle - transfer handle to identify part of transfer
598 * @param[in] transferOpFlag - flag to indicate which part of data being
599 * transferred
600 * @param[in] instanceID - instance ID to identify the command
601 * @param[in] biosJsonDir - path where the BIOS json files are present
602 */
603Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
604 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500605 uint32_t /*transferHandle*/,
606 uint8_t /*transferOpFlag*/, uint8_t instanceID,
607 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500608{
609 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
610 0);
611 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
612 uint32_t nxtTransferHandle = 0;
613 uint8_t transferFlag = PLDM_START_AND_END;
614 size_t respPayloadLength{};
615
616 if (BIOSAttributeTable.isEmpty())
617 { // no persisted table, constructing fresh table and response
618 auto attributeTable =
619 bios_type_enum::constructAttrTable(BIOSStringTable, biosJsonDir);
620
621 // calculate pad
622 uint8_t padSize = utils::getNumPadBytes(attributeTable.size());
623 std::vector<uint8_t> pad(padSize, 0);
624 if (padSize)
625 {
626 std::move(pad.begin(), pad.end(),
627 std::back_inserter(attributeTable));
628 }
629
630 if (!attributeTable.empty())
631 {
632 // compute checksum
633 boost::crc_32_type result;
634 size_t size = attributeTable.size();
635 result.process_bytes(attributeTable.data(), size);
636 uint32_t checkSum = result.checksum();
637 attributeTable.resize(size + sizeof(checkSum));
638 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
639 attributeTable.data() + size);
640 BIOSAttributeTable.store(attributeTable);
641 }
642 response.resize(sizeof(pldm_msg_hdr) +
643 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
644 attributeTable.size());
645 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
646 respPayloadLength = response.size();
647 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
648 transferFlag, attributeTable.data(),
649 respPayloadLength, responsePtr);
650 }
651 else
652 { // persisted table present, constructing response
653 respPayloadLength = response.size();
654 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
655 transferFlag, nullptr, respPayloadLength,
656 responsePtr); // filling up the header here
657 BIOSAttributeTable.load(response);
658 }
659
660 return response;
661}
662
663/** @brief Construct the BIOS attribute value table
664 *
665 * @param[in] BIOSAttributeValueTable - the attribute value table
666 * @param[in] BIOSAttributeTable - the attribute table
667 * @param[in] BIOSStringTable - the string table
668 * @param[in] transferHandle - transfer handle to identify part of transfer
669 * @param[in] transferOpFlag - flag to indicate which part of data being
670 * transferred
671 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500672 */
673Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
674 const BIOSTable& BIOSAttributeTable,
675 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500676 uint32_t& /*transferHandle*/,
677 uint8_t& /*transferOpFlag*/,
678 uint8_t instanceID,
679 const char* /*biosJsonDir*/)
Sampa Misrab37be312019-07-03 02:26:41 -0500680{
681 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
682 0);
683 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
684 uint32_t nxtTransferHandle = 0;
685 uint8_t transferFlag = PLDM_START_AND_END;
686 size_t respPayloadLength{};
687
688 if (BIOSAttributeValueTable.isEmpty())
689 { // no persisted table, constructing fresh table and data
690 Table attributeValueTable = bios_type_enum::constructAttrValueTable(
691 BIOSAttributeTable, BIOSStringTable);
692 // calculate pad
693 uint8_t padSize = utils::getNumPadBytes(attributeValueTable.size());
694 std::vector<uint8_t> pad(padSize, 0);
695 if (padSize)
696 {
697 std::move(pad.begin(), pad.end(),
698 std::back_inserter(attributeValueTable));
699 }
700 if (!attributeValueTable.empty())
701 {
702 // compute checksum
703 boost::crc_32_type result;
704 result.process_bytes(attributeValueTable.data(),
705 attributeValueTable.size());
706 uint32_t checkSum = result.checksum();
707 size_t size = attributeValueTable.size();
708 attributeValueTable.resize(size + sizeof(checkSum));
709 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
710 attributeValueTable.data() + size);
711 BIOSAttributeValueTable.store(attributeValueTable);
712 }
713
714 response.resize(sizeof(pldm_msg_hdr) +
715 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
716 attributeValueTable.size());
717 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
718 respPayloadLength = response.size();
719 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
720 transferFlag, attributeValueTable.data(),
721 respPayloadLength, responsePtr);
722 }
723 else
724 { // persisted table present, constructing response
725 respPayloadLength = response.size();
726 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
727 transferFlag, nullptr, respPayloadLength,
728 responsePtr); // filling up the header here
729 BIOSAttributeValueTable.load(response);
730 }
731
732 return response;
733}
734
735Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
736{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500737 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500738 auto response = internal::buildBIOSTables(request, payloadLength,
739 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
740
741 return response;
742}
743
744namespace bios
745{
746
747void registerHandlers()
748{
749 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
750 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
751}
752
753namespace internal
754{
755
756Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
757 const char* biosJsonDir, const char* biosTablePath)
758{
759 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
760 0);
761 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
762
763 uint32_t transferHandle{};
764 uint8_t transferOpFlag{};
765 uint8_t tableType{};
766
767 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
768 &transferOpFlag, &tableType);
769 if (rc == PLDM_SUCCESS)
770 {
771 BIOSTable BIOSStringTable(
772 ((std::string(biosTablePath) + "/stringTable")).c_str());
773 BIOSTable BIOSAttributeTable(
774 ((std::string(biosTablePath) + "/attributeTable")).c_str());
775 BIOSTable BIOSAttributeValueTable(
776 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
777 switch (tableType)
778 {
779 case PLDM_BIOS_STRING_TABLE:
780
781 response = getBIOSStringTable(
782 BIOSStringTable, transferHandle, transferOpFlag,
783 request->hdr.instance_id, biosJsonDir);
784 break;
785 case PLDM_BIOS_ATTR_TABLE:
786
787 if (BIOSStringTable.isEmpty())
788 {
789 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
790 }
791 else
792 {
793 response = getBIOSAttributeTable(
794 BIOSAttributeTable, BIOSStringTable, transferHandle,
795 transferOpFlag, request->hdr.instance_id, biosJsonDir);
796 }
797 break;
798 case PLDM_BIOS_ATTR_VAL_TABLE:
799 if (BIOSAttributeTable.isEmpty())
800 {
801 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
802 }
803 else
804 {
805 response = getBIOSAttributeValueTable(
806 BIOSAttributeValueTable, BIOSAttributeTable,
807 BIOSStringTable, transferHandle, transferOpFlag,
808 request->hdr.instance_id, biosJsonDir);
809 }
810 break;
811 default:
812 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
813 break;
814 }
815 }
816
817 if (rc != PLDM_SUCCESS)
818 {
819 uint32_t nxtTransferHandle{};
820 uint8_t transferFlag{};
821 size_t respPayloadLength{};
822
823 encode_get_bios_table_resp(request->hdr.instance_id, rc,
824 nxtTransferHandle, transferFlag, nullptr,
825 respPayloadLength, responsePtr);
826 }
827
828 return response;
829}
830
831} // end namespace internal
832} // namespace bios
833
Sampa Misra032bd502019-03-06 05:03:22 -0600834} // namespace responder
835} // namespace pldm