blob: 31b4ec0158b1d3d43cddc3ce73a71ee02dfbb6d2 [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
John Wang3ad21752019-10-06 16:42:21 +0800488void constructAttrValueEntry(
489 const struct pldm_bios_attr_table_entry* attrTableEntry,
490 const std::string& attrName, const BIOSTable& BIOSStringTable,
491 Table& attrValueTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500492{
John Wang3ad21752019-10-06 16:42:21 +0800493 CurrentValues currVals;
494 try
Sampa Misrab37be312019-07-03 02:26:41 -0500495 {
John Wang3ad21752019-10-06 16:42:21 +0800496 currVals = getAttrValue(attrName);
Sampa Misrab37be312019-07-03 02:26:41 -0500497 }
John Wang3ad21752019-10-06 16:42:21 +0800498 catch (const std::exception& e)
499 {
500 log<level::ERR>("getAttrValue returned error for attribute",
501 entry("NAME=%s", attrName.c_str()),
502 entry("ERROR=%s", e.what()));
503 return;
504 }
505 uint8_t pv_num =
506 pldm_bios_table_attr_entry_enum_decode_pv_num(attrTableEntry);
507 PossibleValuesByHandle pvHdls(pv_num, 0);
508 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrTableEntry,
509 pvHdls.data(), pv_num);
510 std::sort(currVals.begin(), currVals.end());
511
512 auto currValStrIndices = findStrIndices(pvHdls, currVals, BIOSStringTable);
513
514 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
515 currValStrIndices.size());
516 auto tableSize = attrValueTable.size();
517 attrValueTable.resize(tableSize + entryLength);
518 pldm_bios_table_attr_value_entry_encode_enum(
519 attrValueTable.data() + tableSize, entryLength,
520 attrTableEntry->attr_handle, attrTableEntry->attr_type,
521 currValStrIndices.size(), currValStrIndices.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500522}
523
524} // end namespace bios_type_enum
525
Carol Wangdc220c82019-08-26 13:31:31 +0800526namespace bios_type_string
527{
Carol Wang612f35b2019-08-26 17:14:26 +0800528
529using namespace bios_parser::bios_string;
530
Carol Wangdc220c82019-08-26 13:31:31 +0800531/** @brief Construct the attibute table for BIOS type String and
532 * String ReadOnly
533 * @param[in] BIOSStringTable - the string table
534 * @param[in] biosJsonDir - path where the BIOS json files are present
535 * @param[in,out] attributeTable - the attribute table
536 *
537 */
Carol Wang612f35b2019-08-26 17:14:26 +0800538void constructAttrTable(const BIOSTable& BIOSStringTable,
539 const char* biosJsonDir, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800540{
Carol Wang612f35b2019-08-26 17:14:26 +0800541 auto rc = setupValueLookup(biosJsonDir);
542 if (rc == -1)
543 {
544 log<level::ERR>("Failed to parse entries in Json file");
545 return;
546 }
547 const auto& attributeMap = getValues();
548 StringHandle strHandle;
549
550 for (const auto& [key, value] : attributeMap)
551 {
552 try
553 {
554 strHandle = findStringHandle(key, BIOSStringTable);
555 }
556 catch (InternalFailure& e)
557 {
558 log<level::ERR>("Could not find handle for BIOS string",
559 entry("ATTRIBUTE=%s", key.c_str()));
560 continue;
561 }
562
563 const auto& [type, strType, minStrLen, maxStrLen, defaultStrLen,
564 defaultStr] = value;
565 uint8_t typeOfAttr =
566 type ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
567
568 BIOSTableRow stringAttrTable(bios_parser::bios_string::attrTableSize +
569 defaultStr.size());
570 BIOSTableRow::iterator it = stringAttrTable.begin();
571 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
572 stringAttrTable.data());
573 attrPtr->attr_handle = nextAttributeHandle();
574 attrPtr->attr_type = typeOfAttr;
575 attrPtr->string_handle = strHandle;
576
577 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
578 std::copy_n(&strType, sizeof(uint8_t), it);
579 std::advance(it, sizeof(uint8_t));
580 std::copy_n(reinterpret_cast<const uint8_t*>(&minStrLen),
581 sizeof(uint16_t), it);
582 std::advance(it, sizeof(uint16_t));
583 std::copy_n(reinterpret_cast<const uint8_t*>(&maxStrLen),
584 sizeof(uint16_t), it);
585 std::advance(it, sizeof(uint16_t));
586 std::copy_n(reinterpret_cast<const uint8_t*>(&defaultStrLen),
587 sizeof(uint16_t), it);
588 std::advance(it, sizeof(uint16_t));
589 std::copy_n(defaultStr.data(), defaultStr.size(), it);
590 std::advance(it, defaultStr.size());
591
592 attributeTable.insert(attributeTable.end(), stringAttrTable.begin(),
593 stringAttrTable.end());
594 }
Carol Wangdc220c82019-08-26 13:31:31 +0800595}
Carol Wangb503f9e2019-09-02 16:34:10 +0800596
John Wang3ad21752019-10-06 16:42:21 +0800597void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
598 const std::string& attrName,
Carol Wangb503f9e2019-09-02 16:34:10 +0800599 const BIOSTable& BIOSStringTable,
John Wang3ad21752019-10-06 16:42:21 +0800600 Table& attrValueTable)
Carol Wangb503f9e2019-09-02 16:34:10 +0800601{
John Wang3ad21752019-10-06 16:42:21 +0800602 std::ignore = BIOSStringTable;
603 std::string currStr;
604 uint16_t currStrLen = 0;
605 try
Carol Wangb503f9e2019-09-02 16:34:10 +0800606 {
John Wang3ad21752019-10-06 16:42:21 +0800607 currStr = getAttrValue(attrName);
608 currStrLen = currStr.size();
Carol Wangb503f9e2019-09-02 16:34:10 +0800609 }
John Wang3ad21752019-10-06 16:42:21 +0800610 catch (const std::exception& e)
611 {
612 log<level::ERR>("getAttrValue returned error for attribute",
613 entry("NAME=%s", attrName.c_str()),
614 entry("ERROR=%s", e.what()));
615 return;
616 }
617 auto entryLength =
618 pldm_bios_table_attr_value_entry_encode_string_length(currStrLen);
619 auto tableSize = attrValueTable.size();
620 attrValueTable.resize(tableSize + entryLength);
621 pldm_bios_table_attr_value_entry_encode_string(
622 attrValueTable.data() + tableSize, entryLength,
623 attrTableEntry->attr_handle, attrTableEntry->attr_type, currStrLen,
624 currStr.c_str());
Carol Wangb503f9e2019-09-02 16:34:10 +0800625}
626
Carol Wangdc220c82019-08-26 13:31:31 +0800627} // end namespace bios_type_string
628
John Wang02700402019-10-06 16:34:29 +0800629void traverseBIOSAttrTable(const Table& biosAttrTable,
630 AttrTableEntryHandler handler)
631{
632 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
633 iter(pldm_bios_table_iter_create(biosAttrTable.data(),
634 biosAttrTable.size(),
635 PLDM_BIOS_ATTR_TABLE),
636 pldm_bios_table_iter_free);
637 while (!pldm_bios_table_iter_is_end(iter.get()))
638 {
639 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
640 try
641 {
642 handler(table_entry);
643 }
644 catch (const std::exception& e)
645 {
646 log<level::ERR>("handler fails when traversing BIOSAttrTable",
647 entry("ERROR=%s", e.what()));
648 }
649 pldm_bios_table_iter_next(iter.get());
650 }
651}
652
Carol Wangdc220c82019-08-26 13:31:31 +0800653using typeHandler =
654 std::function<void(const BIOSTable& BIOSStringTable,
655 const char* biosJsonDir, Table& attributeTable)>;
656std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
657 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
658 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}};
659
Sampa Misrab37be312019-07-03 02:26:41 -0500660/** @brief Construct the BIOS attribute table
661 *
662 * @param[in] BIOSAttributeTable - the attribute table
663 * @param[in] BIOSStringTable - the string table
664 * @param[in] transferHandle - transfer handle to identify part of transfer
665 * @param[in] transferOpFlag - flag to indicate which part of data being
666 * transferred
667 * @param[in] instanceID - instance ID to identify the command
668 * @param[in] biosJsonDir - path where the BIOS json files are present
669 */
670Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
671 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500672 uint32_t /*transferHandle*/,
673 uint8_t /*transferOpFlag*/, uint8_t instanceID,
674 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500675{
676 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
677 0);
678 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
679 uint32_t nxtTransferHandle = 0;
680 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500681
682 if (BIOSAttributeTable.isEmpty())
683 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800684 Table attributeTable;
685 fs::path dir(biosJsonDir);
686
687 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
688 it++)
689 {
690 fs::path file = dir / it->first;
691 if (fs::exists(file))
692 {
693 it->second(BIOSStringTable, biosJsonDir, attributeTable);
694 }
695 }
696
697 if (attributeTable.empty())
698 { // no available json file is found
699 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
700 nxtTransferHandle, transferFlag, nullptr,
701 response.size(), responsePtr);
702 return response;
703 }
John Wangc2938352019-09-30 13:58:41 +0800704 utils::padAndChecksum(attributeTable);
705 BIOSAttributeTable.store(attributeTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500706 response.resize(sizeof(pldm_msg_hdr) +
707 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
708 attributeTable.size());
709 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500710 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
711 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800712 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500713 }
714 else
715 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500716 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800717 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500718 responsePtr); // filling up the header here
719 BIOSAttributeTable.load(response);
720 }
721
722 return response;
723}
724
John Wang3ad21752019-10-06 16:42:21 +0800725using AttrValTableEntryConstructHandler =
726 std::function<void(const struct pldm_bios_attr_table_entry* tableEntry,
727 const std::string& attrName,
728 const BIOSTable& BIOSStringTable, Table& table)>;
729
730using AttrType = uint8_t;
731const std::map<AttrType, AttrValTableEntryConstructHandler>
732 AttrValTableConstructMap{
733 {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry},
734 {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry},
735 {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry},
736 {PLDM_BIOS_ENUMERATION_READ_ONLY,
737 bios_type_enum::constructAttrValueEntry},
738 };
739
740void constructAttrValueTableEntry(
741 const struct pldm_bios_attr_table_entry* attrEntry,
742 const BIOSTable& BIOSStringTable, Table& attributeValueTable)
743{
744 auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable);
745 if (attrName.empty())
746 {
747 log<level::ERR>("invalid string handle",
748 entry("STRING_HANDLE=%d", attrEntry->string_handle));
749 return;
750 }
751
752 AttrValTableConstructMap.at(attrEntry->attr_type)(
753 attrEntry, attrName, BIOSStringTable, attributeValueTable);
754}
755
Sampa Misrab37be312019-07-03 02:26:41 -0500756/** @brief Construct the BIOS attribute value table
757 *
758 * @param[in] BIOSAttributeValueTable - the attribute value table
759 * @param[in] BIOSAttributeTable - the attribute table
760 * @param[in] BIOSStringTable - the string table
761 * @param[in] transferHandle - transfer handle to identify part of transfer
762 * @param[in] transferOpFlag - flag to indicate which part of data being
763 * transferred
764 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500765 */
766Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
767 const BIOSTable& BIOSAttributeTable,
768 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500769 uint32_t& /*transferHandle*/,
770 uint8_t& /*transferOpFlag*/,
John Wang3ad21752019-10-06 16:42:21 +0800771 uint8_t instanceID)
Sampa Misrab37be312019-07-03 02:26:41 -0500772{
773 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
774 0);
775 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
776 uint32_t nxtTransferHandle = 0;
777 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500778
John Wang3ad21752019-10-06 16:42:21 +0800779 if (!BIOSAttributeValueTable.isEmpty())
780 {
Sampa Misrab37be312019-07-03 02:26:41 -0500781 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
John Wang3ad21752019-10-06 16:42:21 +0800782 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500783 responsePtr); // filling up the header here
784 BIOSAttributeValueTable.load(response);
John Wang3ad21752019-10-06 16:42:21 +0800785 return response;
Sampa Misrab37be312019-07-03 02:26:41 -0500786 }
787
John Wang3ad21752019-10-06 16:42:21 +0800788 Table attributeValueTable;
789 Table attributeTable;
790 BIOSAttributeTable.load(attributeTable);
791 traverseBIOSAttrTable(
792 attributeTable,
793 [&BIOSStringTable, &attributeValueTable](
794 const struct pldm_bios_attr_table_entry* tableEntry) {
795 constructAttrValueTableEntry(tableEntry, BIOSStringTable,
796 attributeValueTable);
797 });
798 if (attributeValueTable.empty())
799 {
800 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
801 nxtTransferHandle, transferFlag, nullptr,
802 response.size(), responsePtr);
803 return response;
804 }
805 utils::padAndChecksum(attributeValueTable);
806 BIOSAttributeValueTable.store(attributeValueTable);
807
808 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
809 attributeValueTable.size());
810 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
811 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
812 transferFlag, attributeValueTable.data(),
813 response.size(), responsePtr);
814
Sampa Misrab37be312019-07-03 02:26:41 -0500815 return response;
816}
817
818Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
819{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500820 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500821 auto response = internal::buildBIOSTables(request, payloadLength,
822 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
823
824 return response;
825}
826
827namespace bios
828{
829
830void registerHandlers()
831{
832 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
833 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
834}
835
836namespace internal
837{
838
839Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
840 const char* biosJsonDir, const char* biosTablePath)
841{
842 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
843 0);
844 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
845
846 uint32_t transferHandle{};
847 uint8_t transferOpFlag{};
848 uint8_t tableType{};
849
850 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
851 &transferOpFlag, &tableType);
852 if (rc == PLDM_SUCCESS)
853 {
854 BIOSTable BIOSStringTable(
855 ((std::string(biosTablePath) + "/stringTable")).c_str());
856 BIOSTable BIOSAttributeTable(
857 ((std::string(biosTablePath) + "/attributeTable")).c_str());
858 BIOSTable BIOSAttributeValueTable(
859 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
860 switch (tableType)
861 {
862 case PLDM_BIOS_STRING_TABLE:
863
864 response = getBIOSStringTable(
865 BIOSStringTable, transferHandle, transferOpFlag,
866 request->hdr.instance_id, biosJsonDir);
867 break;
868 case PLDM_BIOS_ATTR_TABLE:
869
870 if (BIOSStringTable.isEmpty())
871 {
872 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
873 }
874 else
875 {
876 response = getBIOSAttributeTable(
877 BIOSAttributeTable, BIOSStringTable, transferHandle,
878 transferOpFlag, request->hdr.instance_id, biosJsonDir);
879 }
880 break;
881 case PLDM_BIOS_ATTR_VAL_TABLE:
882 if (BIOSAttributeTable.isEmpty())
883 {
884 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
885 }
886 else
887 {
888 response = getBIOSAttributeValueTable(
889 BIOSAttributeValueTable, BIOSAttributeTable,
890 BIOSStringTable, transferHandle, transferOpFlag,
John Wang3ad21752019-10-06 16:42:21 +0800891 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500892 }
893 break;
894 default:
895 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
896 break;
897 }
898 }
899
900 if (rc != PLDM_SUCCESS)
901 {
902 uint32_t nxtTransferHandle{};
903 uint8_t transferFlag{};
904 size_t respPayloadLength{};
905
906 encode_get_bios_table_resp(request->hdr.instance_id, rc,
907 nxtTransferHandle, transferFlag, nullptr,
908 respPayloadLength, responsePtr);
909 }
910
911 return response;
912}
913
914} // end namespace internal
915} // namespace bios
916
Sampa Misra032bd502019-03-06 05:03:22 -0600917} // namespace responder
918} // namespace pldm