blob: 8b37e359ab87ce283cb8f0f91c997b0ab2da52df [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
Carol Wangb503f9e2019-09-02 16:34:10 +0800482 * @param[in, out] attributeValueTable - the attribute value table
Sampa Misrab37be312019-07-03 02:26:41 -0500483 *
Sampa Misrab37be312019-07-03 02:26:41 -0500484 */
Carol Wangb503f9e2019-09-02 16:34:10 +0800485void constructAttrValueTable(const BIOSTable& BIOSAttributeTable,
486 const BIOSTable& BIOSStringTable,
487 Table& attributeValueTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500488{
Sampa Misrab37be312019-07-03 02:26:41 -0500489 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));
Carol Wangb503f9e2019-09-02 16:34:10 +0800521 return;
Sampa Misrab37be312019-07-03 02:26:41 -0500522 }
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 {
Carol Wangb503f9e2019-09-02 16:34:10 +0800541 return;
Sampa Misrab37be312019-07-03 02:26:41 -0500542 }
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 }
Sampa Misrab37be312019-07-03 02:26:41 -0500586}
587
588} // end namespace bios_type_enum
589
Carol Wangdc220c82019-08-26 13:31:31 +0800590namespace bios_type_string
591{
Carol Wang612f35b2019-08-26 17:14:26 +0800592
593using namespace bios_parser::bios_string;
594
Carol Wangdc220c82019-08-26 13:31:31 +0800595/** @brief Construct the attibute table for BIOS type String and
596 * String ReadOnly
597 * @param[in] BIOSStringTable - the string table
598 * @param[in] biosJsonDir - path where the BIOS json files are present
599 * @param[in,out] attributeTable - the attribute table
600 *
601 */
Carol Wang612f35b2019-08-26 17:14:26 +0800602void constructAttrTable(const BIOSTable& BIOSStringTable,
603 const char* biosJsonDir, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800604{
Carol Wang612f35b2019-08-26 17:14:26 +0800605 auto rc = setupValueLookup(biosJsonDir);
606 if (rc == -1)
607 {
608 log<level::ERR>("Failed to parse entries in Json file");
609 return;
610 }
611 const auto& attributeMap = getValues();
612 StringHandle strHandle;
613
614 for (const auto& [key, value] : attributeMap)
615 {
616 try
617 {
618 strHandle = findStringHandle(key, BIOSStringTable);
619 }
620 catch (InternalFailure& e)
621 {
622 log<level::ERR>("Could not find handle for BIOS string",
623 entry("ATTRIBUTE=%s", key.c_str()));
624 continue;
625 }
626
627 const auto& [type, strType, minStrLen, maxStrLen, defaultStrLen,
628 defaultStr] = value;
629 uint8_t typeOfAttr =
630 type ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
631
632 BIOSTableRow stringAttrTable(bios_parser::bios_string::attrTableSize +
633 defaultStr.size());
634 BIOSTableRow::iterator it = stringAttrTable.begin();
635 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
636 stringAttrTable.data());
637 attrPtr->attr_handle = nextAttributeHandle();
638 attrPtr->attr_type = typeOfAttr;
639 attrPtr->string_handle = strHandle;
640
641 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
642 std::copy_n(&strType, sizeof(uint8_t), it);
643 std::advance(it, sizeof(uint8_t));
644 std::copy_n(reinterpret_cast<const uint8_t*>(&minStrLen),
645 sizeof(uint16_t), it);
646 std::advance(it, sizeof(uint16_t));
647 std::copy_n(reinterpret_cast<const uint8_t*>(&maxStrLen),
648 sizeof(uint16_t), it);
649 std::advance(it, sizeof(uint16_t));
650 std::copy_n(reinterpret_cast<const uint8_t*>(&defaultStrLen),
651 sizeof(uint16_t), it);
652 std::advance(it, sizeof(uint16_t));
653 std::copy_n(defaultStr.data(), defaultStr.size(), it);
654 std::advance(it, defaultStr.size());
655
656 attributeTable.insert(attributeTable.end(), stringAttrTable.begin(),
657 stringAttrTable.end());
658 }
Carol Wangdc220c82019-08-26 13:31:31 +0800659}
Carol Wangb503f9e2019-09-02 16:34:10 +0800660
661/** @brief Construct the attibute value table for BIOS type String and
662 * String ReadOnly
663 *
664 * @param[in] BIOSAttributeTable - the attribute table
665 * @param[in] BIOSStringTable - the string table
666 * @param[in, out] attributeValueTable - the attribute value table
667 *
668 */
669void constructAttrValueTable(const BIOSTable& BIOSAttributeTable,
670 const BIOSTable& BIOSStringTable,
671 Table& attributeValueTable)
672{
673 Response response;
674 BIOSAttributeTable.load(response);
675
676 auto dataPtr = response.data();
677 size_t tableLen = response.size();
678
679 while (true)
680 {
681 auto attrPtr =
682 reinterpret_cast<struct pldm_bios_attr_table_entry*>(dataPtr);
683 uint16_t attrHdl = attrPtr->attr_handle;
684 uint8_t attrType = attrPtr->attr_type;
685 uint16_t stringHdl = attrPtr->string_handle;
686 dataPtr += (sizeof(struct pldm_bios_attr_table_entry) - 1);
687 // pass number of StringType, MinimumStringLength, MaximumStringLength
688 dataPtr += sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint16_t);
689 auto sizeDefaultStr = *(reinterpret_cast<uint16_t*>(dataPtr));
690 // pass number of DefaultStringLength, DefaultString
691 dataPtr += sizeof(uint16_t) + sizeDefaultStr;
692
693 auto attrName = findStringName(stringHdl, BIOSStringTable);
694 if (attrName.empty())
695 {
696 if (std::distance(dataPtr, response.data() + tableLen) <=
697 padChksumMax)
698 {
699 log<level::ERR>("Did not find string name for handle",
700 entry("STRING_HANDLE=%d", stringHdl));
701 return;
702 }
703 continue;
704 }
705
706 uint16_t currStrLen = 0;
707 std::string currStr;
708 try
709 {
710 currStr = getAttrValue(attrName);
711 currStrLen = currStr.size();
712 }
713 catch (const std::exception& e)
714 {
715 log<level::ERR>("getAttrValue returned error for attribute",
716 entry("NAME=%s", attrName.c_str()),
717 entry("ERROR=%s", e.what()));
718 if (std::distance(dataPtr, response.data() + tableLen) <=
719 padChksumMax)
720 {
721 return;
722 }
723 continue;
724 }
725
726 BIOSTableRow strAttrValTable(
727 bios_parser::bios_string::attrValueTableSize + currStrLen, 0);
728 BIOSTableRow::iterator it = strAttrValTable.begin();
729 auto attrValPtr =
730 reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
731 strAttrValTable.data());
732 attrValPtr->attr_handle = attrHdl;
733 attrValPtr->attr_type = attrType;
734 std::advance(it, (sizeof(pldm_bios_attr_val_table_entry) - 1));
735 std::copy_n(reinterpret_cast<uint8_t*>(&currStrLen), sizeof(uint16_t),
736 it);
737 std::advance(it, sizeof(uint16_t));
738 if (currStrLen)
739 {
740 std::copy_n(currStr.cbegin(), currStrLen, it);
741 std::advance(it, currStrLen);
742 }
743
744 attributeValueTable.insert(attributeValueTable.end(),
745 strAttrValTable.begin(),
746 strAttrValTable.end());
747
748 if (std::distance(dataPtr, response.data() + tableLen) <= padChksumMax)
749 {
750 break;
751 }
752 }
753}
754
Carol Wangdc220c82019-08-26 13:31:31 +0800755} // end namespace bios_type_string
756
757using typeHandler =
758 std::function<void(const BIOSTable& BIOSStringTable,
759 const char* biosJsonDir, Table& attributeTable)>;
760std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
761 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
762 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}};
763
Carol Wang69d3e7f2019-09-04 16:43:15 +0800764using valueHandler = std::function<void(const BIOSTable& BIOSAttributeTable,
Carol Wangb503f9e2019-09-02 16:34:10 +0800765
Carol Wang69d3e7f2019-09-04 16:43:15 +0800766 const BIOSTable& BIOSStringTable,
Carol Wangb503f9e2019-09-02 16:34:10 +0800767
Carol Wang69d3e7f2019-09-04 16:43:15 +0800768 Table& attributeTable)>;
Carol Wangb503f9e2019-09-02 16:34:10 +0800769
Carol Wang69d3e7f2019-09-04 16:43:15 +0800770std::map<BIOSJsonName, valueHandler> attrValueHandlers{
Carol Wangb503f9e2019-09-02 16:34:10 +0800771 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrValueTable},
772 {bios_parser::bIOSStrJson, bios_type_string::constructAttrValueTable}};
773
Sampa Misrab37be312019-07-03 02:26:41 -0500774/** @brief Construct the BIOS attribute table
775 *
776 * @param[in] BIOSAttributeTable - the attribute table
777 * @param[in] BIOSStringTable - the string table
778 * @param[in] transferHandle - transfer handle to identify part of transfer
779 * @param[in] transferOpFlag - flag to indicate which part of data being
780 * transferred
781 * @param[in] instanceID - instance ID to identify the command
782 * @param[in] biosJsonDir - path where the BIOS json files are present
783 */
784Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
785 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500786 uint32_t /*transferHandle*/,
787 uint8_t /*transferOpFlag*/, uint8_t instanceID,
788 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500789{
790 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
791 0);
792 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
793 uint32_t nxtTransferHandle = 0;
794 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500795
796 if (BIOSAttributeTable.isEmpty())
797 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800798 Table attributeTable;
799 fs::path dir(biosJsonDir);
800
801 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
802 it++)
803 {
804 fs::path file = dir / it->first;
805 if (fs::exists(file))
806 {
807 it->second(BIOSStringTable, biosJsonDir, attributeTable);
808 }
809 }
810
811 if (attributeTable.empty())
812 { // no available json file is found
813 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
814 nxtTransferHandle, transferFlag, nullptr,
815 response.size(), responsePtr);
816 return response;
817 }
Sampa Misrab37be312019-07-03 02:26:41 -0500818
819 // calculate pad
820 uint8_t padSize = utils::getNumPadBytes(attributeTable.size());
821 std::vector<uint8_t> pad(padSize, 0);
822 if (padSize)
823 {
824 std::move(pad.begin(), pad.end(),
825 std::back_inserter(attributeTable));
826 }
827
828 if (!attributeTable.empty())
829 {
830 // compute checksum
831 boost::crc_32_type result;
832 size_t size = attributeTable.size();
833 result.process_bytes(attributeTable.data(), size);
834 uint32_t checkSum = result.checksum();
835 attributeTable.resize(size + sizeof(checkSum));
836 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
837 attributeTable.data() + size);
838 BIOSAttributeTable.store(attributeTable);
839 }
840 response.resize(sizeof(pldm_msg_hdr) +
841 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
842 attributeTable.size());
843 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500844 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
845 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800846 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500847 }
848 else
849 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500850 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800851 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500852 responsePtr); // filling up the header here
853 BIOSAttributeTable.load(response);
854 }
855
856 return response;
857}
858
859/** @brief Construct the BIOS attribute value table
860 *
861 * @param[in] BIOSAttributeValueTable - the attribute value table
862 * @param[in] BIOSAttributeTable - the attribute table
863 * @param[in] BIOSStringTable - the string table
864 * @param[in] transferHandle - transfer handle to identify part of transfer
865 * @param[in] transferOpFlag - flag to indicate which part of data being
866 * transferred
867 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500868 */
869Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
870 const BIOSTable& BIOSAttributeTable,
871 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500872 uint32_t& /*transferHandle*/,
873 uint8_t& /*transferOpFlag*/,
Carol Wangb503f9e2019-09-02 16:34:10 +0800874 uint8_t instanceID, const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500875{
876 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
877 0);
878 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
879 uint32_t nxtTransferHandle = 0;
880 uint8_t transferFlag = PLDM_START_AND_END;
881 size_t respPayloadLength{};
882
883 if (BIOSAttributeValueTable.isEmpty())
884 { // no persisted table, constructing fresh table and data
Carol Wangb503f9e2019-09-02 16:34:10 +0800885 Table attributeValueTable;
886 fs::path dir(biosJsonDir);
887
888 for (auto it = attrValueHandlers.begin(); it != attrValueHandlers.end();
889 it++)
890 {
891 fs::path file = dir / it->first;
892 if (fs::exists(file))
893 {
894 it->second(BIOSAttributeTable, BIOSStringTable,
895 attributeValueTable);
896 }
897 }
898
899 if (attributeValueTable.empty())
900 { // no available json file is found
901 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
902 nxtTransferHandle, transferFlag, nullptr,
903 response.size(), responsePtr);
904 return response;
905 }
Sampa Misrab37be312019-07-03 02:26:41 -0500906 // calculate pad
907 uint8_t padSize = utils::getNumPadBytes(attributeValueTable.size());
908 std::vector<uint8_t> pad(padSize, 0);
909 if (padSize)
910 {
911 std::move(pad.begin(), pad.end(),
912 std::back_inserter(attributeValueTable));
913 }
914 if (!attributeValueTable.empty())
915 {
916 // compute checksum
917 boost::crc_32_type result;
918 result.process_bytes(attributeValueTable.data(),
919 attributeValueTable.size());
920 uint32_t checkSum = result.checksum();
921 size_t size = attributeValueTable.size();
922 attributeValueTable.resize(size + sizeof(checkSum));
923 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
924 attributeValueTable.data() + size);
925 BIOSAttributeValueTable.store(attributeValueTable);
926 }
927
928 response.resize(sizeof(pldm_msg_hdr) +
929 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
930 attributeValueTable.size());
931 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
932 respPayloadLength = response.size();
933 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
934 transferFlag, attributeValueTable.data(),
935 respPayloadLength, responsePtr);
936 }
937 else
938 { // persisted table present, constructing response
939 respPayloadLength = response.size();
940 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
941 transferFlag, nullptr, respPayloadLength,
942 responsePtr); // filling up the header here
943 BIOSAttributeValueTable.load(response);
944 }
945
946 return response;
947}
948
949Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
950{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500951 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500952 auto response = internal::buildBIOSTables(request, payloadLength,
953 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
954
955 return response;
956}
957
958namespace bios
959{
960
961void registerHandlers()
962{
963 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
964 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
965}
966
967namespace internal
968{
969
970Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
971 const char* biosJsonDir, const char* biosTablePath)
972{
973 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
974 0);
975 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
976
977 uint32_t transferHandle{};
978 uint8_t transferOpFlag{};
979 uint8_t tableType{};
980
981 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
982 &transferOpFlag, &tableType);
983 if (rc == PLDM_SUCCESS)
984 {
985 BIOSTable BIOSStringTable(
986 ((std::string(biosTablePath) + "/stringTable")).c_str());
987 BIOSTable BIOSAttributeTable(
988 ((std::string(biosTablePath) + "/attributeTable")).c_str());
989 BIOSTable BIOSAttributeValueTable(
990 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
991 switch (tableType)
992 {
993 case PLDM_BIOS_STRING_TABLE:
994
995 response = getBIOSStringTable(
996 BIOSStringTable, transferHandle, transferOpFlag,
997 request->hdr.instance_id, biosJsonDir);
998 break;
999 case PLDM_BIOS_ATTR_TABLE:
1000
1001 if (BIOSStringTable.isEmpty())
1002 {
1003 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
1004 }
1005 else
1006 {
1007 response = getBIOSAttributeTable(
1008 BIOSAttributeTable, BIOSStringTable, transferHandle,
1009 transferOpFlag, request->hdr.instance_id, biosJsonDir);
1010 }
1011 break;
1012 case PLDM_BIOS_ATTR_VAL_TABLE:
1013 if (BIOSAttributeTable.isEmpty())
1014 {
1015 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
1016 }
1017 else
1018 {
1019 response = getBIOSAttributeValueTable(
1020 BIOSAttributeValueTable, BIOSAttributeTable,
1021 BIOSStringTable, transferHandle, transferOpFlag,
1022 request->hdr.instance_id, biosJsonDir);
1023 }
1024 break;
1025 default:
1026 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
1027 break;
1028 }
1029 }
1030
1031 if (rc != PLDM_SUCCESS)
1032 {
1033 uint32_t nxtTransferHandle{};
1034 uint8_t transferFlag{};
1035 size_t respPayloadLength{};
1036
1037 encode_get_bios_table_resp(request->hdr.instance_id, rc,
1038 nxtTransferHandle, transferFlag, nullptr,
1039 respPayloadLength, responsePtr);
1040 }
1041
1042 return response;
1043}
1044
1045} // end namespace internal
1046} // namespace bios
1047
Sampa Misra032bd502019-03-06 05:03:22 -06001048} // namespace responder
1049} // namespace pldm