blob: e0ded598cbb1a5f435051cab77f8a7c2085c7c71 [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>
John Wang02700402019-10-06 16:34:29 +080011#include <memory>
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
John Wangc2938352019-09-30 13:58:41 +080058size_t getTableTotalsize(size_t sizeWithoutPad)
59{
60 auto padSize = getNumPadBytes(sizeWithoutPad);
61 return sizeWithoutPad + padSize + sizeof(uint32_t) /* checksum */;
62}
63
64void padAndChecksum(Table& table)
65{
66 auto padSize = getNumPadBytes(table.size());
67 table.insert(table.end(), padSize, 0);
68
69 boost::crc_32_type result;
70 size_t size = table.size();
71 result.process_bytes(table.data(), size);
72 uint32_t checkSum = result.checksum();
73 uint8_t* checkSumPtr = reinterpret_cast<uint8_t*>(&checkSum);
74 table.insert(table.end(), checkSumPtr, checkSumPtr + sizeof(checkSum));
75}
76
Sampa Misra032bd502019-03-06 05:03:22 -060077} // namespace utils
78
Deepak Kodihalli3c275e12019-09-21 06:39:39 -050079Response getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -060080{
81 uint8_t seconds = 0;
82 uint8_t minutes = 0;
83 uint8_t hours = 0;
84 uint8_t day = 0;
85 uint8_t month = 0;
86 uint16_t year = 0;
87
88 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liu408c3c42019-10-16 16:49:15 +080089 constexpr auto hostTimePath = "/xyz/openbmc_project/time/host";
vkaverapa6575b82019-04-03 05:33:52 -050090 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
91 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misra032bd502019-03-06 05:03:22 -060092 std::variant<EpochTimeUS> value;
93
94 auto bus = sdbusplus::bus::new_default();
95 try
96 {
George Liu408c3c42019-10-16 16:49:15 +080097 auto service = getService(bus, hostTimePath, timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -060098
George Liu408c3c42019-10-16 16:49:15 +080099 auto method = bus.new_method_call(service.c_str(), hostTimePath,
Sampa Misra032bd502019-03-06 05:03:22 -0600100 dbusProperties, "Get");
101 method.append(timeInterface, "Elapsed");
102
103 auto reply = bus.call(method);
104 reply.read(value);
105 }
106
107 catch (std::exception& e)
108 {
George Liu408c3c42019-10-16 16:49:15 +0800109 log<level::ERR>("Error getting time", entry("PATH=%s", hostTimePath),
Sampa Misra032bd502019-03-06 05:03:22 -0600110 entry("TIME INTERACE=%s", timeInterface));
111
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530112 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
113 minutes, hours, day, month, year,
114 responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500115 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600116 }
117
118 uint64_t timeUsec = std::get<EpochTimeUS>(value);
119
120 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
121 std::chrono::microseconds(timeUsec))
122 .count();
123
124 utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
125
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530126 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
127 minutes, hours, day, month, year, responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500128 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600129}
130
Sampa Misrab37be312019-07-03 02:26:41 -0500131/** @brief Construct the BIOS string table
132 *
133 * @param[in] BIOSStringTable - the string table
134 * @param[in] transferHandle - transfer handle to identify part of transfer
135 * @param[in] transferOpFlag - flag to indicate which part of data being
136 * transferred
137 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500138 */
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500139Response getBIOSStringTable(BIOSTable& BIOSStringTable,
140 uint32_t /*transferHandle*/,
John Wange96e7e52019-10-05 17:47:30 +0800141 uint8_t /*transferOpFlag*/, uint8_t instanceID)
142
Sampa Misrab37be312019-07-03 02:26:41 -0500143{
144 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
145 0);
146 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
John Wangdd9a6282019-10-11 18:52:46 +0800147 if (!BIOSStringTable.isEmpty())
148 {
149 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS,
150 0, /* next transfer handle */
151 PLDM_START_AND_END, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500152 responsePtr); // filling up the header here
153 BIOSStringTable.load(response);
John Wangdd9a6282019-10-11 18:52:46 +0800154 return response;
155 }
156 auto biosStrings = bios_parser::getStrings();
157 std::sort(biosStrings.begin(), biosStrings.end());
158 // remove all duplicate strings received from bios json
159 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
160 biosStrings.end());
161
162 size_t sizeWithoutPad = std::accumulate(
163 biosStrings.begin(), biosStrings.end(), 0,
164 [](size_t sum, const std::string& elem) {
165 return sum +
166 pldm_bios_table_string_entry_encode_length(elem.length());
167 });
168
169 Table stringTable;
170 stringTable.reserve(utils::getTableTotalsize(sizeWithoutPad));
171
172 stringTable.resize(sizeWithoutPad);
173 auto tablePtr = stringTable.data();
174 for (const auto& elem : biosStrings)
175 {
176 auto entry_length =
177 pldm_bios_table_string_entry_encode_length(elem.length());
178 pldm_bios_table_string_entry_encode(tablePtr, sizeWithoutPad,
179 elem.c_str(), elem.length());
180 tablePtr += entry_length;
181 sizeWithoutPad -= entry_length;
Sampa Misrab37be312019-07-03 02:26:41 -0500182 }
183
John Wangdd9a6282019-10-11 18:52:46 +0800184 utils::padAndChecksum(stringTable);
185 BIOSStringTable.store(stringTable);
186 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
187 stringTable.size(),
188 0);
189 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
190 encode_get_bios_table_resp(
191 instanceID, PLDM_SUCCESS, 0 /* nxtTransferHandle */, PLDM_START_AND_END,
192 stringTable.data(), response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500193 return response;
194}
195
196/** @brief Find the string handle from the BIOS string table given the name
197 *
198 * @param[in] name - name of the BIOS string
199 * @param[in] BIOSStringTable - the string table
200 * @return - uint16_t - handle of the string
201 */
202StringHandle findStringHandle(const std::string& name,
203 const BIOSTable& BIOSStringTable)
204{
John Wangdd9a6282019-10-11 18:52:46 +0800205 Table table;
206 BIOSStringTable.load(table);
207 auto stringEntry = pldm_bios_table_string_find_by_string(
208 table.data(), table.size(), name.c_str());
209 if (stringEntry == nullptr)
Sampa Misrab37be312019-07-03 02:26:41 -0500210 {
John Wangdd9a6282019-10-11 18:52:46 +0800211 log<level::ERR>("Reached end of BIOS string table,did not find the "
212 "handle for the string",
213 entry("STRING=%s", name.c_str()));
214 elog<InternalFailure>();
Sampa Misrab37be312019-07-03 02:26:41 -0500215 }
John Wangdd9a6282019-10-11 18:52:46 +0800216
217 return pldm_bios_table_string_entry_decode_handle(stringEntry);
Sampa Misrab37be312019-07-03 02:26:41 -0500218}
219
220/** @brief Find the string name from the BIOS string table for a string handle
221 *
222 * @param[in] stringHdl - string handle
223 * @param[in] BIOSStringTable - the string table
224 *
225 * @return - std::string - name of the corresponding BIOS string
226 */
227std::string findStringName(StringHandle stringHdl,
228 const BIOSTable& BIOSStringTable)
229{
John Wangdd9a6282019-10-11 18:52:46 +0800230 Table table;
231 BIOSStringTable.load(table);
232 auto stringEntry = pldm_bios_table_string_find_by_handle(
233 table.data(), table.size(), stringHdl);
Sampa Misrab37be312019-07-03 02:26:41 -0500234 std::string name;
John Wangdd9a6282019-10-11 18:52:46 +0800235 if (stringEntry == nullptr)
Sampa Misrab37be312019-07-03 02:26:41 -0500236 {
John Wangdd9a6282019-10-11 18:52:46 +0800237 log<level::ERR>("Reached end of BIOS string table,did not find "
238 "string name for handle",
239 entry("STRING_HANDLE=%d", stringHdl));
Sampa Misrab37be312019-07-03 02:26:41 -0500240 }
John Wangdd9a6282019-10-11 18:52:46 +0800241 auto strLength =
242 pldm_bios_table_string_entry_decode_string_length(stringEntry);
243 name.resize(strLength);
244 pldm_bios_table_string_entry_decode_string(stringEntry, name.data(),
245 name.size());
Sampa Misrab37be312019-07-03 02:26:41 -0500246 return name;
247}
248
249namespace bios_type_enum
250{
251
Carol Wangdc220c82019-08-26 13:31:31 +0800252using namespace bios_parser::bios_enum;
253
Sampa Misrab37be312019-07-03 02:26:41 -0500254/** @brief Find the indices into the array of the possible values of string
255 * handles for the current values.This is used in attribute value table
256 *
257 * @param[in] possiVals - vector of string handles comprising all the possible
258 * values for an attribute
259 * @param[in] currVals - vector of strings comprising all current values
260 * for an attribute
261 * @param[in] BIOSStringTable - the string table
262 *
263 * @return - std::vector<uint8_t> - indices into the array of the possible
264 * values of string handles
265 */
266std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
267 CurrentValues currVals,
268 const BIOSTable& BIOSStringTable)
269{
270 std::vector<uint8_t> stringIndices;
271
272 for (const auto& currVal : currVals)
273 {
274 StringHandle curHdl;
275 try
276 {
277 curHdl = findStringHandle(currVal, BIOSStringTable);
278 }
279 catch (InternalFailure& e)
280 {
281 log<level::ERR>("Exception fetching handle for the string",
282 entry("STRING=%s", currVal.c_str()));
283 continue;
284 }
285
286 uint8_t i = 0;
287 for (auto possiHdl : possiVals)
288 {
289 if (possiHdl == curHdl)
290 {
291 stringIndices.push_back(i);
292 break;
293 }
294 i++;
295 }
296 }
297 return stringIndices;
298}
299
300/** @brief Find the indices into the array of the possible values of string
301 * handles for the default values. This is used in attribute table
302 *
303 * @param[in] possiVals - vector of strings comprising all the possible values
304 * for an attribute
305 * @param[in] defVals - vector of strings comprising all the default values
306 * for an attribute
307 * @return - std::vector<uint8_t> - indices into the array of the possible
308 * values of string
309 */
310std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
311 const DefaultValues& defVals)
312{
313 std::vector<uint8_t> defHdls;
314 for (const auto& defs : defVals)
315 {
316 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
317 if (index != possiVals.end())
318 {
319 defHdls.push_back(index - possiVals.begin());
320 }
321 }
322
323 return defHdls;
324}
325
326/** @brief Construct the attibute table for BIOS type Enumeration and
327 * Enumeration ReadOnly
328 * @param[in] BIOSStringTable - the string table
329 * @param[in] biosJsonDir - path where the BIOS json files are present
Carol Wangdc220c82019-08-26 13:31:31 +0800330 * @param[in,out] attributeTable - the attribute table
Sampa Misrab37be312019-07-03 02:26:41 -0500331 *
Sampa Misrab37be312019-07-03 02:26:41 -0500332 */
John Wange96e7e52019-10-05 17:47:30 +0800333void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500334{
Sampa Misrab37be312019-07-03 02:26:41 -0500335 const auto& attributeMap = getValues();
Sampa Misrab37be312019-07-03 02:26:41 -0500336 StringHandle strHandle;
337
338 for (const auto& [key, value] : attributeMap)
339 {
340 try
341 {
342 strHandle = findStringHandle(key, BIOSStringTable);
343 }
344 catch (InternalFailure& e)
345 {
346 log<level::ERR>("Could not find handle for BIOS string",
347 entry("ATTRIBUTE=%s", key.c_str()));
348 continue;
349 }
John Wangccc04552019-10-14 14:28:25 +0800350 bool readOnly = (std::get<0>(value));
Sampa Misrab37be312019-07-03 02:26:41 -0500351 PossibleValues possiVals = std::get<1>(value);
352 DefaultValues defVals = std::get<2>(value);
353 // both the possible and default values are stored in sorted manner to
354 // ease in fetching back/comparison
355 std::sort(possiVals.begin(), possiVals.end());
356 std::sort(defVals.begin(), defVals.end());
357
358 std::vector<StringHandle> possiValsByHdl;
359 for (const auto& elem : possiVals)
360 {
361 try
362 {
363 auto hdl = findStringHandle(elem, BIOSStringTable);
364 possiValsByHdl.push_back(std::move(hdl));
365 }
366 catch (InternalFailure& e)
367 {
368 log<level::ERR>("Could not find handle for BIOS string",
369 entry("STRING=%s", elem.c_str()));
370 continue;
371 }
372 }
373 auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
John Wangccc04552019-10-14 14:28:25 +0800374 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
375 possiValsByHdl.size(), defValsByHdl.size());
Sampa Misrab37be312019-07-03 02:26:41 -0500376
John Wangccc04552019-10-14 14:28:25 +0800377 auto attrTableSize = attributeTable.size();
378 attributeTable.resize(attrTableSize + entryLength, 0);
379 struct pldm_bios_table_attr_entry_enum_info info = {
380 strHandle,
381 readOnly,
382 (uint8_t)possiValsByHdl.size(),
383 possiValsByHdl.data(),
384 (uint8_t)defValsByHdl.size(),
385 defValsByHdl.data(),
386 };
387 pldm_bios_table_attr_entry_enum_encode(
388 attributeTable.data() + attrTableSize, entryLength, &info);
Sampa Misrab37be312019-07-03 02:26:41 -0500389 }
Sampa Misrab37be312019-07-03 02:26:41 -0500390}
391
John Wang3ad21752019-10-06 16:42:21 +0800392void constructAttrValueEntry(
393 const struct pldm_bios_attr_table_entry* attrTableEntry,
394 const std::string& attrName, const BIOSTable& BIOSStringTable,
395 Table& attrValueTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500396{
John Wang3ad21752019-10-06 16:42:21 +0800397 CurrentValues currVals;
398 try
Sampa Misrab37be312019-07-03 02:26:41 -0500399 {
John Wang3ad21752019-10-06 16:42:21 +0800400 currVals = getAttrValue(attrName);
Sampa Misrab37be312019-07-03 02:26:41 -0500401 }
John Wang3ad21752019-10-06 16:42:21 +0800402 catch (const std::exception& e)
403 {
404 log<level::ERR>("getAttrValue returned error for attribute",
405 entry("NAME=%s", attrName.c_str()),
406 entry("ERROR=%s", e.what()));
407 return;
408 }
409 uint8_t pv_num =
410 pldm_bios_table_attr_entry_enum_decode_pv_num(attrTableEntry);
411 PossibleValuesByHandle pvHdls(pv_num, 0);
412 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrTableEntry,
413 pvHdls.data(), pv_num);
414 std::sort(currVals.begin(), currVals.end());
415
416 auto currValStrIndices = findStrIndices(pvHdls, currVals, BIOSStringTable);
417
418 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
419 currValStrIndices.size());
420 auto tableSize = attrValueTable.size();
421 attrValueTable.resize(tableSize + entryLength);
422 pldm_bios_table_attr_value_entry_encode_enum(
423 attrValueTable.data() + tableSize, entryLength,
424 attrTableEntry->attr_handle, attrTableEntry->attr_type,
425 currValStrIndices.size(), currValStrIndices.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500426}
427
428} // end namespace bios_type_enum
429
Carol Wangdc220c82019-08-26 13:31:31 +0800430namespace bios_type_string
431{
Carol Wang612f35b2019-08-26 17:14:26 +0800432
433using namespace bios_parser::bios_string;
434
Carol Wangdc220c82019-08-26 13:31:31 +0800435/** @brief Construct the attibute table for BIOS type String and
436 * String ReadOnly
437 * @param[in] BIOSStringTable - the string table
438 * @param[in] biosJsonDir - path where the BIOS json files are present
439 * @param[in,out] attributeTable - the attribute table
440 *
441 */
John Wange96e7e52019-10-05 17:47:30 +0800442void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800443{
Carol Wang612f35b2019-08-26 17:14:26 +0800444 const auto& attributeMap = getValues();
445 StringHandle strHandle;
Carol Wang612f35b2019-08-26 17:14:26 +0800446 for (const auto& [key, value] : attributeMap)
447 {
448 try
449 {
450 strHandle = findStringHandle(key, BIOSStringTable);
451 }
452 catch (InternalFailure& e)
453 {
454 log<level::ERR>("Could not find handle for BIOS string",
455 entry("ATTRIBUTE=%s", key.c_str()));
456 continue;
457 }
458
John Wangccc04552019-10-14 14:28:25 +0800459 const auto& [readOnly, strType, minStrLen, maxStrLen, defaultStrLen,
Carol Wang612f35b2019-08-26 17:14:26 +0800460 defaultStr] = value;
John Wangccc04552019-10-14 14:28:25 +0800461 auto entryLength =
462 pldm_bios_table_attr_entry_string_encode_length(defaultStrLen);
Carol Wang612f35b2019-08-26 17:14:26 +0800463
John Wangccc04552019-10-14 14:28:25 +0800464 struct pldm_bios_table_attr_entry_string_info info = {
465 strHandle, readOnly, strType, minStrLen,
466 maxStrLen, defaultStrLen, defaultStr.data(),
467 };
468 auto attrTableSize = attributeTable.size();
469 attributeTable.resize(attrTableSize + entryLength, 0);
470 pldm_bios_table_attr_entry_string_encode(
471 attributeTable.data() + attrTableSize, entryLength, &info);
Carol Wang612f35b2019-08-26 17:14:26 +0800472 }
Carol Wangdc220c82019-08-26 13:31:31 +0800473}
Carol Wangb503f9e2019-09-02 16:34:10 +0800474
John Wang3ad21752019-10-06 16:42:21 +0800475void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
476 const std::string& attrName,
Carol Wangb503f9e2019-09-02 16:34:10 +0800477 const BIOSTable& BIOSStringTable,
John Wang3ad21752019-10-06 16:42:21 +0800478 Table& attrValueTable)
Carol Wangb503f9e2019-09-02 16:34:10 +0800479{
John Wang3ad21752019-10-06 16:42:21 +0800480 std::ignore = BIOSStringTable;
481 std::string currStr;
482 uint16_t currStrLen = 0;
483 try
Carol Wangb503f9e2019-09-02 16:34:10 +0800484 {
John Wang3ad21752019-10-06 16:42:21 +0800485 currStr = getAttrValue(attrName);
486 currStrLen = currStr.size();
Carol Wangb503f9e2019-09-02 16:34:10 +0800487 }
John Wang3ad21752019-10-06 16:42:21 +0800488 catch (const std::exception& e)
489 {
490 log<level::ERR>("getAttrValue returned error for attribute",
491 entry("NAME=%s", attrName.c_str()),
492 entry("ERROR=%s", e.what()));
493 return;
494 }
495 auto entryLength =
496 pldm_bios_table_attr_value_entry_encode_string_length(currStrLen);
497 auto tableSize = attrValueTable.size();
498 attrValueTable.resize(tableSize + entryLength);
499 pldm_bios_table_attr_value_entry_encode_string(
500 attrValueTable.data() + tableSize, entryLength,
501 attrTableEntry->attr_handle, attrTableEntry->attr_type, currStrLen,
502 currStr.c_str());
Carol Wangb503f9e2019-09-02 16:34:10 +0800503}
504
Carol Wangdc220c82019-08-26 13:31:31 +0800505} // end namespace bios_type_string
506
John Wang02700402019-10-06 16:34:29 +0800507void traverseBIOSAttrTable(const Table& biosAttrTable,
508 AttrTableEntryHandler handler)
509{
510 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
511 iter(pldm_bios_table_iter_create(biosAttrTable.data(),
512 biosAttrTable.size(),
513 PLDM_BIOS_ATTR_TABLE),
514 pldm_bios_table_iter_free);
515 while (!pldm_bios_table_iter_is_end(iter.get()))
516 {
517 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
518 try
519 {
520 handler(table_entry);
521 }
522 catch (const std::exception& e)
523 {
524 log<level::ERR>("handler fails when traversing BIOSAttrTable",
525 entry("ERROR=%s", e.what()));
526 }
527 pldm_bios_table_iter_next(iter.get());
528 }
529}
530
John Wange96e7e52019-10-05 17:47:30 +0800531using typeHandler = std::function<void(const BIOSTable& BIOSStringTable,
532 Table& attributeTable)>;
Carol Wangdc220c82019-08-26 13:31:31 +0800533std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
534 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
535 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}};
536
Sampa Misrab37be312019-07-03 02:26:41 -0500537/** @brief Construct the BIOS attribute table
538 *
539 * @param[in] BIOSAttributeTable - the attribute table
540 * @param[in] BIOSStringTable - the string table
541 * @param[in] transferHandle - transfer handle to identify part of transfer
542 * @param[in] transferOpFlag - flag to indicate which part of data being
543 * transferred
544 * @param[in] instanceID - instance ID to identify the command
545 * @param[in] biosJsonDir - path where the BIOS json files are present
546 */
547Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
548 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500549 uint32_t /*transferHandle*/,
550 uint8_t /*transferOpFlag*/, uint8_t instanceID,
551 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500552{
553 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
554 0);
555 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
556 uint32_t nxtTransferHandle = 0;
557 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500558
559 if (BIOSAttributeTable.isEmpty())
560 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800561 Table attributeTable;
562 fs::path dir(biosJsonDir);
563
564 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
565 it++)
566 {
567 fs::path file = dir / it->first;
568 if (fs::exists(file))
569 {
John Wange96e7e52019-10-05 17:47:30 +0800570 it->second(BIOSStringTable, attributeTable);
Carol Wangdc220c82019-08-26 13:31:31 +0800571 }
572 }
573
574 if (attributeTable.empty())
575 { // no available json file is found
576 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
577 nxtTransferHandle, transferFlag, nullptr,
578 response.size(), responsePtr);
579 return response;
580 }
John Wangc2938352019-09-30 13:58:41 +0800581 utils::padAndChecksum(attributeTable);
582 BIOSAttributeTable.store(attributeTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500583 response.resize(sizeof(pldm_msg_hdr) +
584 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
585 attributeTable.size());
586 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500587 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
588 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800589 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500590 }
591 else
592 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500593 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800594 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500595 responsePtr); // filling up the header here
596 BIOSAttributeTable.load(response);
597 }
598
599 return response;
600}
601
John Wang3ad21752019-10-06 16:42:21 +0800602using AttrValTableEntryConstructHandler =
603 std::function<void(const struct pldm_bios_attr_table_entry* tableEntry,
604 const std::string& attrName,
605 const BIOSTable& BIOSStringTable, Table& table)>;
606
607using AttrType = uint8_t;
608const std::map<AttrType, AttrValTableEntryConstructHandler>
609 AttrValTableConstructMap{
610 {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry},
611 {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry},
612 {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry},
613 {PLDM_BIOS_ENUMERATION_READ_ONLY,
614 bios_type_enum::constructAttrValueEntry},
615 };
616
617void constructAttrValueTableEntry(
618 const struct pldm_bios_attr_table_entry* attrEntry,
619 const BIOSTable& BIOSStringTable, Table& attributeValueTable)
620{
621 auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable);
622 if (attrName.empty())
623 {
624 log<level::ERR>("invalid string handle",
625 entry("STRING_HANDLE=%d", attrEntry->string_handle));
626 return;
627 }
628
629 AttrValTableConstructMap.at(attrEntry->attr_type)(
630 attrEntry, attrName, BIOSStringTable, attributeValueTable);
631}
632
Sampa Misrab37be312019-07-03 02:26:41 -0500633/** @brief Construct the BIOS attribute value table
634 *
635 * @param[in] BIOSAttributeValueTable - the attribute value table
636 * @param[in] BIOSAttributeTable - the attribute table
637 * @param[in] BIOSStringTable - the string table
638 * @param[in] transferHandle - transfer handle to identify part of transfer
639 * @param[in] transferOpFlag - flag to indicate which part of data being
640 * transferred
641 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500642 */
643Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
644 const BIOSTable& BIOSAttributeTable,
645 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500646 uint32_t& /*transferHandle*/,
647 uint8_t& /*transferOpFlag*/,
John Wang3ad21752019-10-06 16:42:21 +0800648 uint8_t instanceID)
Sampa Misrab37be312019-07-03 02:26:41 -0500649{
650 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
651 0);
652 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
653 uint32_t nxtTransferHandle = 0;
654 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500655
John Wang3ad21752019-10-06 16:42:21 +0800656 if (!BIOSAttributeValueTable.isEmpty())
657 {
Sampa Misrab37be312019-07-03 02:26:41 -0500658 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
John Wang3ad21752019-10-06 16:42:21 +0800659 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500660 responsePtr); // filling up the header here
661 BIOSAttributeValueTable.load(response);
John Wang3ad21752019-10-06 16:42:21 +0800662 return response;
Sampa Misrab37be312019-07-03 02:26:41 -0500663 }
664
John Wang3ad21752019-10-06 16:42:21 +0800665 Table attributeValueTable;
666 Table attributeTable;
667 BIOSAttributeTable.load(attributeTable);
668 traverseBIOSAttrTable(
669 attributeTable,
670 [&BIOSStringTable, &attributeValueTable](
671 const struct pldm_bios_attr_table_entry* tableEntry) {
672 constructAttrValueTableEntry(tableEntry, BIOSStringTable,
673 attributeValueTable);
674 });
675 if (attributeValueTable.empty())
676 {
677 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
678 nxtTransferHandle, transferFlag, nullptr,
679 response.size(), responsePtr);
680 return response;
681 }
682 utils::padAndChecksum(attributeValueTable);
683 BIOSAttributeValueTable.store(attributeValueTable);
684
685 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
686 attributeValueTable.size());
687 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
688 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
689 transferFlag, attributeValueTable.data(),
690 response.size(), responsePtr);
691
Sampa Misrab37be312019-07-03 02:26:41 -0500692 return response;
693}
694
695Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
696{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500697 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500698 auto response = internal::buildBIOSTables(request, payloadLength,
699 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
700
701 return response;
702}
703
704namespace bios
705{
706
707void registerHandlers()
708{
709 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
710 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
711}
712
713namespace internal
714{
715
716Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
717 const char* biosJsonDir, const char* biosTablePath)
718{
719 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
720 0);
721 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
722
John Wange96e7e52019-10-05 17:47:30 +0800723 if (setupConfig(biosJsonDir) != 0)
724 {
725 encode_get_bios_table_resp(
726 request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE,
727 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr,
728 response.size(), responsePtr);
729 return response;
730 }
731
Sampa Misrab37be312019-07-03 02:26:41 -0500732 uint32_t transferHandle{};
733 uint8_t transferOpFlag{};
734 uint8_t tableType{};
735
736 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
737 &transferOpFlag, &tableType);
738 if (rc == PLDM_SUCCESS)
739 {
740 BIOSTable BIOSStringTable(
741 ((std::string(biosTablePath) + "/stringTable")).c_str());
742 BIOSTable BIOSAttributeTable(
743 ((std::string(biosTablePath) + "/attributeTable")).c_str());
744 BIOSTable BIOSAttributeValueTable(
745 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
746 switch (tableType)
747 {
748 case PLDM_BIOS_STRING_TABLE:
749
John Wange96e7e52019-10-05 17:47:30 +0800750 response = getBIOSStringTable(BIOSStringTable, transferHandle,
751 transferOpFlag,
752 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500753 break;
754 case PLDM_BIOS_ATTR_TABLE:
755
756 if (BIOSStringTable.isEmpty())
757 {
758 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
759 }
760 else
761 {
762 response = getBIOSAttributeTable(
763 BIOSAttributeTable, BIOSStringTable, transferHandle,
764 transferOpFlag, request->hdr.instance_id, biosJsonDir);
765 }
766 break;
767 case PLDM_BIOS_ATTR_VAL_TABLE:
Carol Wangf7d1a362019-11-18 15:34:14 +0800768 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty())
Sampa Misrab37be312019-07-03 02:26:41 -0500769 {
770 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
771 }
772 else
773 {
774 response = getBIOSAttributeValueTable(
775 BIOSAttributeValueTable, BIOSAttributeTable,
776 BIOSStringTable, transferHandle, transferOpFlag,
John Wang3ad21752019-10-06 16:42:21 +0800777 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500778 }
779 break;
780 default:
781 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
782 break;
783 }
784 }
785
786 if (rc != PLDM_SUCCESS)
787 {
788 uint32_t nxtTransferHandle{};
789 uint8_t transferFlag{};
790 size_t respPayloadLength{};
791
792 encode_get_bios_table_resp(request->hdr.instance_id, rc,
793 nxtTransferHandle, transferFlag, nullptr,
794 respPayloadLength, responsePtr);
795 }
796
797 return response;
798}
799
800} // end namespace internal
801} // namespace bios
802
Sampa Misra032bd502019-03-06 05:03:22 -0600803} // namespace responder
804} // namespace pldm