blob: a133b2d493ccc9e8eb4638639ce525a758db3eb9 [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>
John Wang02700402019-10-06 16:34:29 +080012#include <memory>
Sampa Misrab37be312019-07-03 02:26:41 -050013#include <numeric>
14#include <phosphor-logging/elog-errors.hpp>
Deepak Kodihallic2feac92019-04-30 17:21:19 +053015#include <phosphor-logging/log.hpp>
Sampa Misra032bd502019-03-06 05:03:22 -060016#include <stdexcept>
17#include <string>
18#include <variant>
19#include <vector>
20
Sampa Misrab37be312019-07-03 02:26:41 -050021using namespace pldm::responder::bios;
22using namespace bios_parser;
Sampa Misrab37be312019-07-03 02:26:41 -050023
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>;
Carol Wangdc220c82019-08-26 13:31:31 +080031using BIOSJsonName = std::string;
Sampa Misra032bd502019-03-06 05:03:22 -060032
33constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
Sampa Misrab37be312019-07-03 02:26:41 -050034constexpr auto padChksumMax = 7;
Sampa Misra032bd502019-03-06 05:03:22 -060035
36namespace responder
37{
38
39namespace utils
40{
41
42void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
43 uint8_t& hours, uint8_t& day, uint8_t& month,
44 uint16_t& year)
45{
46 auto t = time_t(timeSec);
47 auto time = localtime(&t);
48
49 seconds = decimalToBcd(time->tm_sec);
50 minutes = decimalToBcd(time->tm_min);
51 hours = decimalToBcd(time->tm_hour);
52 day = decimalToBcd(time->tm_mday);
53 month =
54 decimalToBcd(time->tm_mon + 1); // The number of months in the range
55 // 0 to 11.PLDM expects range 1 to 12
56 year = decimalToBcd(time->tm_year + 1900); // The number of years since 1900
57}
58
John Wangc2938352019-09-30 13:58:41 +080059size_t getTableTotalsize(size_t sizeWithoutPad)
60{
61 auto padSize = getNumPadBytes(sizeWithoutPad);
62 return sizeWithoutPad + padSize + sizeof(uint32_t) /* checksum */;
63}
64
65void padAndChecksum(Table& table)
66{
67 auto padSize = getNumPadBytes(table.size());
68 table.insert(table.end(), padSize, 0);
69
70 boost::crc_32_type result;
71 size_t size = table.size();
72 result.process_bytes(table.data(), size);
73 uint32_t checkSum = result.checksum();
74 uint8_t* checkSumPtr = reinterpret_cast<uint8_t*>(&checkSum);
75 table.insert(table.end(), checkSumPtr, checkSumPtr + sizeof(checkSum));
76}
77
Sampa Misra032bd502019-03-06 05:03:22 -060078} // namespace utils
79
Deepak Kodihalli3c275e12019-09-21 06:39:39 -050080Response getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -060081{
82 uint8_t seconds = 0;
83 uint8_t minutes = 0;
84 uint8_t hours = 0;
85 uint8_t day = 0;
86 uint8_t month = 0;
87 uint16_t year = 0;
88
89 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liu408c3c42019-10-16 16:49:15 +080090 constexpr auto hostTimePath = "/xyz/openbmc_project/time/host";
vkaverapa6575b82019-04-03 05:33:52 -050091 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
92 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misra032bd502019-03-06 05:03:22 -060093 std::variant<EpochTimeUS> value;
94
95 auto bus = sdbusplus::bus::new_default();
96 try
97 {
George Liu408c3c42019-10-16 16:49:15 +080098 auto service = getService(bus, hostTimePath, timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -060099
George Liu408c3c42019-10-16 16:49:15 +0800100 auto method = bus.new_method_call(service.c_str(), hostTimePath,
Sampa Misra032bd502019-03-06 05:03:22 -0600101 dbusProperties, "Get");
102 method.append(timeInterface, "Elapsed");
103
104 auto reply = bus.call(method);
105 reply.read(value);
106 }
107
108 catch (std::exception& e)
109 {
George Liu408c3c42019-10-16 16:49:15 +0800110 log<level::ERR>("Error getting time", entry("PATH=%s", hostTimePath),
Sampa Misra032bd502019-03-06 05:03:22 -0600111 entry("TIME INTERACE=%s", timeInterface));
112
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530113 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
114 minutes, hours, day, month, year,
115 responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500116 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600117 }
118
119 uint64_t timeUsec = std::get<EpochTimeUS>(value);
120
121 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
122 std::chrono::microseconds(timeUsec))
123 .count();
124
125 utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
126
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530127 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
128 minutes, hours, day, month, year, responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500129 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600130}
131
Sampa Misrab37be312019-07-03 02:26:41 -0500132/** @brief Generate the next attribute handle
133 *
134 * @return - uint16_t - next attribute handle
135 */
136AttributeHandle nextAttributeHandle()
137{
138 static AttributeHandle attrHdl = 0;
139 return attrHdl++;
140}
141
142/** @brief Generate the next string handle
143 * *
144 * @return - uint16_t - next string handle
145 */
146StringHandle nextStringHandle()
147{
148 static StringHandle strHdl = 0;
149 return strHdl++;
150}
151
152/** @brief Construct the BIOS string table
153 *
154 * @param[in] BIOSStringTable - the string table
155 * @param[in] transferHandle - transfer handle to identify part of transfer
156 * @param[in] transferOpFlag - flag to indicate which part of data being
157 * transferred
158 * @param[in] instanceID - instance ID to identify the command
159 * @param[in] biosJsonDir - path where the BIOS json files are present
160 */
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500161Response getBIOSStringTable(BIOSTable& BIOSStringTable,
162 uint32_t /*transferHandle*/,
163 uint8_t /*transferOpFlag*/, uint8_t instanceID,
Sampa Misrab37be312019-07-03 02:26:41 -0500164 const char* biosJsonDir)
165{
166 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
167 0);
168 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
169
170 if (BIOSStringTable.isEmpty())
171 { // no persisted table, constructing fresh table and file
172 auto biosStrings = bios_parser::getStrings(biosJsonDir);
John Wangc2938352019-09-30 13:58:41 +0800173 if (biosStrings.empty())
174 {
175 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
176 0, PLDM_START_AND_END, nullptr,
177 response.size(), responsePtr);
178 return response;
179 }
Sampa Misrab37be312019-07-03 02:26:41 -0500180 std::sort(biosStrings.begin(), biosStrings.end());
181 // remove all duplicate strings received from bios json
182 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
183 biosStrings.end());
184 size_t allStringsLen =
185 std::accumulate(biosStrings.begin(), biosStrings.end(), 0,
186 [](size_t sum, const std::string& elem) {
187 return sum + elem.size();
188 });
189 size_t sizeWithoutPad =
190 allStringsLen +
191 (biosStrings.size() * (sizeof(pldm_bios_string_table_entry) - 1));
John Wangc2938352019-09-30 13:58:41 +0800192 Table stringTable;
193 stringTable.reserve(utils::getTableTotalsize(sizeWithoutPad));
194
195 stringTable.resize(sizeWithoutPad);
196 auto tablePtr = stringTable.data();
Sampa Misrab37be312019-07-03 02:26:41 -0500197 for (const auto& elem : biosStrings)
198 {
199 auto stringPtr =
200 reinterpret_cast<struct pldm_bios_string_table_entry*>(
201 tablePtr);
202
203 stringPtr->string_handle = nextStringHandle();
204 stringPtr->string_length = elem.length();
205 memcpy(stringPtr->name, elem.c_str(), elem.length());
206 tablePtr += sizeof(stringPtr->string_handle) +
207 sizeof(stringPtr->string_length);
208 tablePtr += elem.length();
209 }
Sampa Misrab37be312019-07-03 02:26:41 -0500210
John Wangc2938352019-09-30 13:58:41 +0800211 utils::padAndChecksum(stringTable);
212 BIOSStringTable.store(stringTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500213 response.resize(sizeof(pldm_msg_hdr) +
214 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
John Wangc2938352019-09-30 13:58:41 +0800215 stringTable.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500216 0);
217 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
218 size_t respPayloadLength = response.size();
219 uint32_t nxtTransferHandle = 0;
220 uint8_t transferFlag = PLDM_START_AND_END;
221 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
222 transferFlag, stringTable.data(),
223 respPayloadLength, responsePtr);
224 }
225 else
226 { // persisted table present, constructing response
227 size_t respPayloadLength = response.size();
228 uint32_t nxtTransferHandle = 0;
229 uint8_t transferFlag = PLDM_START_AND_END;
230 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
231 transferFlag, nullptr, respPayloadLength,
232 responsePtr); // filling up the header here
233 BIOSStringTable.load(response);
234 }
235
236 return response;
237}
238
239/** @brief Find the string handle from the BIOS string table given the name
240 *
241 * @param[in] name - name of the BIOS string
242 * @param[in] BIOSStringTable - the string table
243 * @return - uint16_t - handle of the string
244 */
245StringHandle findStringHandle(const std::string& name,
246 const BIOSTable& BIOSStringTable)
247{
248 StringHandle hdl{};
249 Response response;
250 BIOSStringTable.load(response);
251
252 auto tableData = response.data();
253 size_t tableLen = response.size();
254 auto tableEntry =
255 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
256 while (1)
257 {
258 hdl = tableEntry->string_handle;
259 uint16_t len = tableEntry->string_length;
John Wangbe6b8022019-09-27 14:20:15 +0800260 if (name.compare(0, name.length(), tableEntry->name, len) == 0)
Sampa Misrab37be312019-07-03 02:26:41 -0500261 {
262 break;
263 }
264 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
265
266 if (std::distance(tableData, response.data() + tableLen) <=
267 padChksumMax)
268 {
269 log<level::ERR>("Reached end of BIOS string table,did not find the "
270 "handle for the string",
271 entry("STRING=%s", name.c_str()));
272 elog<InternalFailure>();
273 break;
274 }
275
276 tableEntry =
277 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
278 }
279 return hdl;
280}
281
282/** @brief Find the string name from the BIOS string table for a string handle
283 *
284 * @param[in] stringHdl - string handle
285 * @param[in] BIOSStringTable - the string table
286 *
287 * @return - std::string - name of the corresponding BIOS string
288 */
289std::string findStringName(StringHandle stringHdl,
290 const BIOSTable& BIOSStringTable)
291{
292 std::string name;
293 Response response;
294 BIOSStringTable.load(response);
295
296 auto tableData = response.data();
297 size_t tableLen = response.size();
298 auto tableEntry =
299 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
300 while (1)
301 {
302 StringHandle currHdl = tableEntry->string_handle;
303 uint16_t len = tableEntry->string_length;
304 if (currHdl == stringHdl)
305 {
306 name.resize(len);
307 memcpy(name.data(), tableEntry->name, len);
308 break;
309 }
310 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
311
312 if (std::distance(tableData, response.data() + tableLen) <=
313 padChksumMax)
314 {
315 log<level::ERR>("Reached end of BIOS string table,did not find "
316 "string name for handle",
317 entry("STRING_HANDLE=%d", stringHdl));
318 break;
319 }
320
321 tableEntry =
322 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
323 }
324 return name;
325}
326
327namespace bios_type_enum
328{
329
Carol Wangdc220c82019-08-26 13:31:31 +0800330using namespace bios_parser::bios_enum;
331
Sampa Misrab37be312019-07-03 02:26:41 -0500332/** @brief Find the indices into the array of the possible values of string
333 * handles for the current values.This is used in attribute value table
334 *
335 * @param[in] possiVals - vector of string handles comprising all the possible
336 * values for an attribute
337 * @param[in] currVals - vector of strings comprising all current values
338 * for an attribute
339 * @param[in] BIOSStringTable - the string table
340 *
341 * @return - std::vector<uint8_t> - indices into the array of the possible
342 * values of string handles
343 */
344std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
345 CurrentValues currVals,
346 const BIOSTable& BIOSStringTable)
347{
348 std::vector<uint8_t> stringIndices;
349
350 for (const auto& currVal : currVals)
351 {
352 StringHandle curHdl;
353 try
354 {
355 curHdl = findStringHandle(currVal, BIOSStringTable);
356 }
357 catch (InternalFailure& e)
358 {
359 log<level::ERR>("Exception fetching handle for the string",
360 entry("STRING=%s", currVal.c_str()));
361 continue;
362 }
363
364 uint8_t i = 0;
365 for (auto possiHdl : possiVals)
366 {
367 if (possiHdl == curHdl)
368 {
369 stringIndices.push_back(i);
370 break;
371 }
372 i++;
373 }
374 }
375 return stringIndices;
376}
377
378/** @brief Find the indices into the array of the possible values of string
379 * handles for the default values. This is used in attribute table
380 *
381 * @param[in] possiVals - vector of strings comprising all the possible values
382 * for an attribute
383 * @param[in] defVals - vector of strings comprising all the default values
384 * for an attribute
385 * @return - std::vector<uint8_t> - indices into the array of the possible
386 * values of string
387 */
388std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
389 const DefaultValues& defVals)
390{
391 std::vector<uint8_t> defHdls;
392 for (const auto& defs : defVals)
393 {
394 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
395 if (index != possiVals.end())
396 {
397 defHdls.push_back(index - possiVals.begin());
398 }
399 }
400
401 return defHdls;
402}
403
404/** @brief Construct the attibute table for BIOS type Enumeration and
405 * Enumeration ReadOnly
406 * @param[in] BIOSStringTable - the string table
407 * @param[in] biosJsonDir - path where the BIOS json files are present
Carol Wangdc220c82019-08-26 13:31:31 +0800408 * @param[in,out] attributeTable - the attribute table
Sampa Misrab37be312019-07-03 02:26:41 -0500409 *
Sampa Misrab37be312019-07-03 02:26:41 -0500410 */
Carol Wangdc220c82019-08-26 13:31:31 +0800411void constructAttrTable(const BIOSTable& BIOSStringTable,
412 const char* biosJsonDir, Table& attributeTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500413{
414 setupValueLookup(biosJsonDir);
415 const auto& attributeMap = getValues();
Sampa Misrab37be312019-07-03 02:26:41 -0500416 StringHandle strHandle;
417
418 for (const auto& [key, value] : attributeMap)
419 {
420 try
421 {
422 strHandle = findStringHandle(key, BIOSStringTable);
423 }
424 catch (InternalFailure& e)
425 {
426 log<level::ERR>("Could not find handle for BIOS string",
427 entry("ATTRIBUTE=%s", key.c_str()));
428 continue;
429 }
430 uint8_t typeOfAttr = (std::get<0>(value))
431 ? PLDM_BIOS_ENUMERATION_READ_ONLY
432 : PLDM_BIOS_ENUMERATION;
433 PossibleValues possiVals = std::get<1>(value);
434 DefaultValues defVals = std::get<2>(value);
435 // both the possible and default values are stored in sorted manner to
436 // ease in fetching back/comparison
437 std::sort(possiVals.begin(), possiVals.end());
438 std::sort(defVals.begin(), defVals.end());
439
440 std::vector<StringHandle> possiValsByHdl;
441 for (const auto& elem : possiVals)
442 {
443 try
444 {
445 auto hdl = findStringHandle(elem, BIOSStringTable);
446 possiValsByHdl.push_back(std::move(hdl));
447 }
448 catch (InternalFailure& e)
449 {
450 log<level::ERR>("Could not find handle for BIOS string",
451 entry("STRING=%s", elem.c_str()));
452 continue;
453 }
454 }
455 auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
456
457 BIOSTableRow enumAttrTable(
458 (sizeof(struct pldm_bios_attr_table_entry) - 1) + sizeof(uint8_t) +
459 possiValsByHdl.size() * sizeof(uint16_t) + sizeof(uint8_t) +
460 defValsByHdl.size() * sizeof(uint8_t),
461 0);
462 BIOSTableRow::iterator it = enumAttrTable.begin();
463 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
464 enumAttrTable.data());
465 attrPtr->attr_handle = nextAttributeHandle();
466 attrPtr->attr_type = typeOfAttr;
467 attrPtr->string_handle = std::move(strHandle);
468 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
469 uint8_t numPossibleVals = possiValsByHdl.size();
470 std::copy_n(&numPossibleVals, sizeof(numPossibleVals), it);
471 std::advance(it, sizeof(numPossibleVals));
472 std::copy_n(reinterpret_cast<uint8_t*>(possiValsByHdl.data()),
473 sizeof(uint16_t) * possiValsByHdl.size(), it);
474 std::advance(
475 it, sizeof(uint16_t) *
476 possiValsByHdl.size()); // possible val handle is uint16_t
477 uint8_t numDefaultVals = defValsByHdl.size();
478 std::copy_n(&numDefaultVals, sizeof(numDefaultVals), it);
479 std::advance(it, sizeof(numDefaultVals));
480 std::copy(defValsByHdl.begin(), defValsByHdl.end(), it);
481 std::advance(it, defValsByHdl.size());
482
483 std::move(enumAttrTable.begin(), enumAttrTable.end(),
484 std::back_inserter(attributeTable));
485 }
Sampa Misrab37be312019-07-03 02:26:41 -0500486}
487
488/** @brief Construct the attibute value table for BIOS type Enumeration and
489 * Enumeration ReadOnly
490 *
491 * @param[in] BIOSAttributeTable - the attribute table
492 * @param[in] BIOSStringTable - the string table
Carol Wangb503f9e2019-09-02 16:34:10 +0800493 * @param[in, out] attributeValueTable - the attribute value table
Sampa Misrab37be312019-07-03 02:26:41 -0500494 *
Sampa Misrab37be312019-07-03 02:26:41 -0500495 */
Carol Wangb503f9e2019-09-02 16:34:10 +0800496void constructAttrValueTable(const BIOSTable& BIOSAttributeTable,
497 const BIOSTable& BIOSStringTable,
498 Table& attributeValueTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500499{
Sampa Misrab37be312019-07-03 02:26:41 -0500500 Response response;
501 BIOSAttributeTable.load(response);
502
503 auto tableData = response.data();
504 size_t tableLen = response.size();
505 auto attrPtr =
506 reinterpret_cast<struct pldm_bios_attr_table_entry*>(response.data());
507
508 while (1)
509 {
510 uint16_t attrHdl = attrPtr->attr_handle;
511 uint8_t attrType = attrPtr->attr_type;
512 uint16_t stringHdl = attrPtr->string_handle;
513 tableData += (sizeof(struct pldm_bios_attr_table_entry) - 1);
514 uint8_t numPossiVals = *tableData;
515 tableData++; // pass number of possible values
516 PossibleValuesByHandle possiValsByHdl(numPossiVals, 0);
517 memcpy(possiValsByHdl.data(), tableData,
518 sizeof(uint16_t) * numPossiVals);
519 tableData += sizeof(uint16_t) * numPossiVals;
520 uint8_t numDefVals = *tableData;
521 tableData++; // pass number of def vals
522 tableData += numDefVals; // pass all the def val indices
523
524 auto attrName = findStringName(stringHdl, BIOSStringTable);
525 if (attrName.empty())
526 {
527 if (std::distance(tableData, response.data() + tableLen) <=
528 padChksumMax)
529 {
530 log<level::ERR>("Did not find string name for handle",
531 entry("STRING_HANDLE=%d", stringHdl));
Carol Wangb503f9e2019-09-02 16:34:10 +0800532 return;
Sampa Misrab37be312019-07-03 02:26:41 -0500533 }
534 attrPtr =
535 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
536 continue;
537 }
538 CurrentValues currVals;
539 try
540 {
541 currVals = getAttrValue(attrName);
542 }
543 catch (const std::exception& e)
544 {
545 log<level::ERR>(
546 "constructAttrValueTable returned error for attribute",
547 entry("NAME=%s", attrName.c_str()),
548 entry("ERROR=%s", e.what()));
549 if (std::distance(tableData, response.data() + tableLen) <=
550 padChksumMax)
551 {
Carol Wangb503f9e2019-09-02 16:34:10 +0800552 return;
Sampa Misrab37be312019-07-03 02:26:41 -0500553 }
554
555 attrPtr =
556 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
557 continue;
558 }
559 // sorting since the possible values are stored in sorted way
560 std::sort(currVals.begin(), currVals.end());
561 auto currValStrIndices =
562 findStrIndices(possiValsByHdl, currVals, BIOSStringTable);
563 // number of current values equals to the number of string handles
564 // received not the number of strings received from getAttrValue
565 uint8_t numCurrVals = currValStrIndices.size();
566
567 BIOSTableRow enumAttrValTable(
568 (sizeof(struct pldm_bios_attr_val_table_entry) - 1) +
569 sizeof(uint8_t) + numCurrVals * sizeof(uint8_t),
570 0);
571 BIOSTableRow::iterator it = enumAttrValTable.begin();
572 auto attrValPtr =
573 reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
574 enumAttrValTable.data());
575 attrValPtr->attr_handle = attrHdl;
576 attrValPtr->attr_type = attrType;
577 std::advance(it, (sizeof(pldm_bios_attr_val_table_entry) - 1));
578 std::copy_n(&numCurrVals, sizeof(numCurrVals), it);
579 std::advance(it, sizeof(numCurrVals));
580 if (numCurrVals)
581 {
582 std::copy(currValStrIndices.begin(), currValStrIndices.end(), it);
583 std::advance(it, currValStrIndices.size());
584 }
585 std::move(enumAttrValTable.begin(), enumAttrValTable.end(),
586 std::back_inserter(attributeValueTable));
587
588 if (std::distance(tableData, response.data() + tableLen) <=
589 padChksumMax)
590 {
591 break;
592 }
593
594 attrPtr =
595 reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
596 }
Sampa Misrab37be312019-07-03 02:26:41 -0500597}
598
599} // end namespace bios_type_enum
600
Carol Wangdc220c82019-08-26 13:31:31 +0800601namespace bios_type_string
602{
Carol Wang612f35b2019-08-26 17:14:26 +0800603
604using namespace bios_parser::bios_string;
605
Carol Wangdc220c82019-08-26 13:31:31 +0800606/** @brief Construct the attibute table for BIOS type String and
607 * String ReadOnly
608 * @param[in] BIOSStringTable - the string table
609 * @param[in] biosJsonDir - path where the BIOS json files are present
610 * @param[in,out] attributeTable - the attribute table
611 *
612 */
Carol Wang612f35b2019-08-26 17:14:26 +0800613void constructAttrTable(const BIOSTable& BIOSStringTable,
614 const char* biosJsonDir, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800615{
Carol Wang612f35b2019-08-26 17:14:26 +0800616 auto rc = setupValueLookup(biosJsonDir);
617 if (rc == -1)
618 {
619 log<level::ERR>("Failed to parse entries in Json file");
620 return;
621 }
622 const auto& attributeMap = getValues();
623 StringHandle strHandle;
624
625 for (const auto& [key, value] : attributeMap)
626 {
627 try
628 {
629 strHandle = findStringHandle(key, BIOSStringTable);
630 }
631 catch (InternalFailure& e)
632 {
633 log<level::ERR>("Could not find handle for BIOS string",
634 entry("ATTRIBUTE=%s", key.c_str()));
635 continue;
636 }
637
638 const auto& [type, strType, minStrLen, maxStrLen, defaultStrLen,
639 defaultStr] = value;
640 uint8_t typeOfAttr =
641 type ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
642
643 BIOSTableRow stringAttrTable(bios_parser::bios_string::attrTableSize +
644 defaultStr.size());
645 BIOSTableRow::iterator it = stringAttrTable.begin();
646 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
647 stringAttrTable.data());
648 attrPtr->attr_handle = nextAttributeHandle();
649 attrPtr->attr_type = typeOfAttr;
650 attrPtr->string_handle = strHandle;
651
652 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
653 std::copy_n(&strType, sizeof(uint8_t), it);
654 std::advance(it, sizeof(uint8_t));
655 std::copy_n(reinterpret_cast<const uint8_t*>(&minStrLen),
656 sizeof(uint16_t), it);
657 std::advance(it, sizeof(uint16_t));
658 std::copy_n(reinterpret_cast<const uint8_t*>(&maxStrLen),
659 sizeof(uint16_t), it);
660 std::advance(it, sizeof(uint16_t));
661 std::copy_n(reinterpret_cast<const uint8_t*>(&defaultStrLen),
662 sizeof(uint16_t), it);
663 std::advance(it, sizeof(uint16_t));
664 std::copy_n(defaultStr.data(), defaultStr.size(), it);
665 std::advance(it, defaultStr.size());
666
667 attributeTable.insert(attributeTable.end(), stringAttrTable.begin(),
668 stringAttrTable.end());
669 }
Carol Wangdc220c82019-08-26 13:31:31 +0800670}
Carol Wangb503f9e2019-09-02 16:34:10 +0800671
672/** @brief Construct the attibute value table for BIOS type String and
673 * String ReadOnly
674 *
675 * @param[in] BIOSAttributeTable - the attribute table
676 * @param[in] BIOSStringTable - the string table
677 * @param[in, out] attributeValueTable - the attribute value table
678 *
679 */
680void constructAttrValueTable(const BIOSTable& BIOSAttributeTable,
681 const BIOSTable& BIOSStringTable,
682 Table& attributeValueTable)
683{
684 Response response;
685 BIOSAttributeTable.load(response);
686
687 auto dataPtr = response.data();
688 size_t tableLen = response.size();
689
690 while (true)
691 {
692 auto attrPtr =
693 reinterpret_cast<struct pldm_bios_attr_table_entry*>(dataPtr);
694 uint16_t attrHdl = attrPtr->attr_handle;
695 uint8_t attrType = attrPtr->attr_type;
696 uint16_t stringHdl = attrPtr->string_handle;
697 dataPtr += (sizeof(struct pldm_bios_attr_table_entry) - 1);
698 // pass number of StringType, MinimumStringLength, MaximumStringLength
699 dataPtr += sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint16_t);
700 auto sizeDefaultStr = *(reinterpret_cast<uint16_t*>(dataPtr));
701 // pass number of DefaultStringLength, DefaultString
702 dataPtr += sizeof(uint16_t) + sizeDefaultStr;
703
704 auto attrName = findStringName(stringHdl, BIOSStringTable);
705 if (attrName.empty())
706 {
707 if (std::distance(dataPtr, response.data() + tableLen) <=
708 padChksumMax)
709 {
710 log<level::ERR>("Did not find string name for handle",
711 entry("STRING_HANDLE=%d", stringHdl));
712 return;
713 }
714 continue;
715 }
716
717 uint16_t currStrLen = 0;
718 std::string currStr;
719 try
720 {
721 currStr = getAttrValue(attrName);
722 currStrLen = currStr.size();
723 }
724 catch (const std::exception& e)
725 {
726 log<level::ERR>("getAttrValue returned error for attribute",
727 entry("NAME=%s", attrName.c_str()),
728 entry("ERROR=%s", e.what()));
729 if (std::distance(dataPtr, response.data() + tableLen) <=
730 padChksumMax)
731 {
732 return;
733 }
734 continue;
735 }
736
737 BIOSTableRow strAttrValTable(
738 bios_parser::bios_string::attrValueTableSize + currStrLen, 0);
739 BIOSTableRow::iterator it = strAttrValTable.begin();
740 auto attrValPtr =
741 reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
742 strAttrValTable.data());
743 attrValPtr->attr_handle = attrHdl;
744 attrValPtr->attr_type = attrType;
745 std::advance(it, (sizeof(pldm_bios_attr_val_table_entry) - 1));
746 std::copy_n(reinterpret_cast<uint8_t*>(&currStrLen), sizeof(uint16_t),
747 it);
748 std::advance(it, sizeof(uint16_t));
749 if (currStrLen)
750 {
751 std::copy_n(currStr.cbegin(), currStrLen, it);
752 std::advance(it, currStrLen);
753 }
754
755 attributeValueTable.insert(attributeValueTable.end(),
756 strAttrValTable.begin(),
757 strAttrValTable.end());
758
759 if (std::distance(dataPtr, response.data() + tableLen) <= padChksumMax)
760 {
761 break;
762 }
763 }
764}
765
Carol Wangdc220c82019-08-26 13:31:31 +0800766} // end namespace bios_type_string
767
John Wang02700402019-10-06 16:34:29 +0800768void traverseBIOSAttrTable(const Table& biosAttrTable,
769 AttrTableEntryHandler handler)
770{
771 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
772 iter(pldm_bios_table_iter_create(biosAttrTable.data(),
773 biosAttrTable.size(),
774 PLDM_BIOS_ATTR_TABLE),
775 pldm_bios_table_iter_free);
776 while (!pldm_bios_table_iter_is_end(iter.get()))
777 {
778 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
779 try
780 {
781 handler(table_entry);
782 }
783 catch (const std::exception& e)
784 {
785 log<level::ERR>("handler fails when traversing BIOSAttrTable",
786 entry("ERROR=%s", e.what()));
787 }
788 pldm_bios_table_iter_next(iter.get());
789 }
790}
791
Carol Wangdc220c82019-08-26 13:31:31 +0800792using typeHandler =
793 std::function<void(const BIOSTable& BIOSStringTable,
794 const char* biosJsonDir, Table& attributeTable)>;
795std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
796 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
797 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}};
798
Carol Wang69d3e7f2019-09-04 16:43:15 +0800799using valueHandler = std::function<void(const BIOSTable& BIOSAttributeTable,
Carol Wangb503f9e2019-09-02 16:34:10 +0800800
Carol Wang69d3e7f2019-09-04 16:43:15 +0800801 const BIOSTable& BIOSStringTable,
Carol Wangb503f9e2019-09-02 16:34:10 +0800802
Carol Wang69d3e7f2019-09-04 16:43:15 +0800803 Table& attributeTable)>;
Carol Wangb503f9e2019-09-02 16:34:10 +0800804
Carol Wang69d3e7f2019-09-04 16:43:15 +0800805std::map<BIOSJsonName, valueHandler> attrValueHandlers{
Carol Wangb503f9e2019-09-02 16:34:10 +0800806 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrValueTable},
807 {bios_parser::bIOSStrJson, bios_type_string::constructAttrValueTable}};
808
Sampa Misrab37be312019-07-03 02:26:41 -0500809/** @brief Construct the BIOS attribute table
810 *
811 * @param[in] BIOSAttributeTable - the attribute table
812 * @param[in] BIOSStringTable - the string table
813 * @param[in] transferHandle - transfer handle to identify part of transfer
814 * @param[in] transferOpFlag - flag to indicate which part of data being
815 * transferred
816 * @param[in] instanceID - instance ID to identify the command
817 * @param[in] biosJsonDir - path where the BIOS json files are present
818 */
819Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
820 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500821 uint32_t /*transferHandle*/,
822 uint8_t /*transferOpFlag*/, uint8_t instanceID,
823 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500824{
825 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
826 0);
827 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
828 uint32_t nxtTransferHandle = 0;
829 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500830
831 if (BIOSAttributeTable.isEmpty())
832 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800833 Table attributeTable;
834 fs::path dir(biosJsonDir);
835
836 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
837 it++)
838 {
839 fs::path file = dir / it->first;
840 if (fs::exists(file))
841 {
842 it->second(BIOSStringTable, biosJsonDir, attributeTable);
843 }
844 }
845
846 if (attributeTable.empty())
847 { // no available json file is found
848 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
849 nxtTransferHandle, transferFlag, nullptr,
850 response.size(), responsePtr);
851 return response;
852 }
John Wangc2938352019-09-30 13:58:41 +0800853 utils::padAndChecksum(attributeTable);
854 BIOSAttributeTable.store(attributeTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500855 response.resize(sizeof(pldm_msg_hdr) +
856 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
857 attributeTable.size());
858 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500859 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
860 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800861 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500862 }
863 else
864 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500865 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800866 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500867 responsePtr); // filling up the header here
868 BIOSAttributeTable.load(response);
869 }
870
871 return response;
872}
873
874/** @brief Construct the BIOS attribute value table
875 *
876 * @param[in] BIOSAttributeValueTable - the attribute value table
877 * @param[in] BIOSAttributeTable - the attribute table
878 * @param[in] BIOSStringTable - the string table
879 * @param[in] transferHandle - transfer handle to identify part of transfer
880 * @param[in] transferOpFlag - flag to indicate which part of data being
881 * transferred
882 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500883 */
884Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
885 const BIOSTable& BIOSAttributeTable,
886 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500887 uint32_t& /*transferHandle*/,
888 uint8_t& /*transferOpFlag*/,
Carol Wangb503f9e2019-09-02 16:34:10 +0800889 uint8_t instanceID, const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500890{
891 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
892 0);
893 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
894 uint32_t nxtTransferHandle = 0;
895 uint8_t transferFlag = PLDM_START_AND_END;
896 size_t respPayloadLength{};
897
898 if (BIOSAttributeValueTable.isEmpty())
899 { // no persisted table, constructing fresh table and data
Carol Wangb503f9e2019-09-02 16:34:10 +0800900 Table attributeValueTable;
901 fs::path dir(biosJsonDir);
902
903 for (auto it = attrValueHandlers.begin(); it != attrValueHandlers.end();
904 it++)
905 {
906 fs::path file = dir / it->first;
907 if (fs::exists(file))
908 {
909 it->second(BIOSAttributeTable, BIOSStringTable,
910 attributeValueTable);
911 }
912 }
913
914 if (attributeValueTable.empty())
915 { // no available json file is found
916 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
917 nxtTransferHandle, transferFlag, nullptr,
918 response.size(), responsePtr);
919 return response;
920 }
Sampa Misrab37be312019-07-03 02:26:41 -0500921 // calculate pad
922 uint8_t padSize = utils::getNumPadBytes(attributeValueTable.size());
923 std::vector<uint8_t> pad(padSize, 0);
924 if (padSize)
925 {
926 std::move(pad.begin(), pad.end(),
927 std::back_inserter(attributeValueTable));
928 }
929 if (!attributeValueTable.empty())
930 {
931 // compute checksum
932 boost::crc_32_type result;
933 result.process_bytes(attributeValueTable.data(),
934 attributeValueTable.size());
935 uint32_t checkSum = result.checksum();
936 size_t size = attributeValueTable.size();
937 attributeValueTable.resize(size + sizeof(checkSum));
938 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
939 attributeValueTable.data() + size);
940 BIOSAttributeValueTable.store(attributeValueTable);
941 }
942
943 response.resize(sizeof(pldm_msg_hdr) +
944 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
945 attributeValueTable.size());
946 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
947 respPayloadLength = response.size();
948 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
949 transferFlag, attributeValueTable.data(),
950 respPayloadLength, responsePtr);
951 }
952 else
953 { // persisted table present, constructing response
954 respPayloadLength = response.size();
955 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
956 transferFlag, nullptr, respPayloadLength,
957 responsePtr); // filling up the header here
958 BIOSAttributeValueTable.load(response);
959 }
960
961 return response;
962}
963
964Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
965{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500966 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500967 auto response = internal::buildBIOSTables(request, payloadLength,
968 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
969
970 return response;
971}
972
973namespace bios
974{
975
976void registerHandlers()
977{
978 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
979 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
980}
981
982namespace internal
983{
984
985Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
986 const char* biosJsonDir, const char* biosTablePath)
987{
988 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
989 0);
990 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
991
992 uint32_t transferHandle{};
993 uint8_t transferOpFlag{};
994 uint8_t tableType{};
995
996 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
997 &transferOpFlag, &tableType);
998 if (rc == PLDM_SUCCESS)
999 {
1000 BIOSTable BIOSStringTable(
1001 ((std::string(biosTablePath) + "/stringTable")).c_str());
1002 BIOSTable BIOSAttributeTable(
1003 ((std::string(biosTablePath) + "/attributeTable")).c_str());
1004 BIOSTable BIOSAttributeValueTable(
1005 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
1006 switch (tableType)
1007 {
1008 case PLDM_BIOS_STRING_TABLE:
1009
1010 response = getBIOSStringTable(
1011 BIOSStringTable, transferHandle, transferOpFlag,
1012 request->hdr.instance_id, biosJsonDir);
1013 break;
1014 case PLDM_BIOS_ATTR_TABLE:
1015
1016 if (BIOSStringTable.isEmpty())
1017 {
1018 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
1019 }
1020 else
1021 {
1022 response = getBIOSAttributeTable(
1023 BIOSAttributeTable, BIOSStringTable, transferHandle,
1024 transferOpFlag, request->hdr.instance_id, biosJsonDir);
1025 }
1026 break;
1027 case PLDM_BIOS_ATTR_VAL_TABLE:
1028 if (BIOSAttributeTable.isEmpty())
1029 {
1030 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
1031 }
1032 else
1033 {
1034 response = getBIOSAttributeValueTable(
1035 BIOSAttributeValueTable, BIOSAttributeTable,
1036 BIOSStringTable, transferHandle, transferOpFlag,
1037 request->hdr.instance_id, biosJsonDir);
1038 }
1039 break;
1040 default:
1041 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
1042 break;
1043 }
1044 }
1045
1046 if (rc != PLDM_SUCCESS)
1047 {
1048 uint32_t nxtTransferHandle{};
1049 uint8_t transferFlag{};
1050 size_t respPayloadLength{};
1051
1052 encode_get_bios_table_resp(request->hdr.instance_id, rc,
1053 nxtTransferHandle, transferFlag, nullptr,
1054 respPayloadLength, responsePtr);
1055 }
1056
1057 return response;
1058}
1059
1060} // end namespace internal
1061} // namespace bios
1062
Sampa Misra032bd502019-03-06 05:03:22 -06001063} // namespace responder
1064} // namespace pldm