blob: c3a1c5368c87f30e49a46b1e1718ff71b7d66b5f [file] [log] [blame]
Sampa Misra032bd502019-03-06 05:03:22 -06001#include "bios.hpp"
2
3#include "libpldmresponder/utils.hpp"
4#include "xyz/openbmc_project/Common/error.hpp"
5
6#include <array>
Sampa Misrab37be312019-07-03 02:26:41 -05007#include <boost/crc.hpp>
Sampa Misra032bd502019-03-06 05:03:22 -06008#include <chrono>
9#include <ctime>
John Wang02700402019-10-06 16:34:29 +080010#include <memory>
Sampa Misrab37be312019-07-03 02:26:41 -050011#include <numeric>
12#include <phosphor-logging/elog-errors.hpp>
Deepak Kodihallic2feac92019-04-30 17:21:19 +053013#include <phosphor-logging/log.hpp>
Sampa Misra032bd502019-03-06 05:03:22 -060014#include <stdexcept>
15#include <string>
16#include <variant>
17#include <vector>
18
Sampa Misrab37be312019-07-03 02:26:41 -050019using namespace pldm::responder::bios;
20using namespace bios_parser;
Sampa Misrab37be312019-07-03 02:26:41 -050021
Sampa Misra032bd502019-03-06 05:03:22 -060022namespace pldm
23{
24
25using namespace phosphor::logging;
Sampa Misrab37be312019-07-03 02:26:41 -050026using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Sampa Misra032bd502019-03-06 05:03:22 -060027using EpochTimeUS = uint64_t;
Sampa Misrab37be312019-07-03 02:26:41 -050028using BIOSTableRow = std::vector<uint8_t>;
Carol Wangdc220c82019-08-26 13:31:31 +080029using BIOSJsonName = std::string;
Sampa Misra032bd502019-03-06 05:03:22 -060030
31constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
Sampa Misrab37be312019-07-03 02:26:41 -050032constexpr auto padChksumMax = 7;
Sampa Misra032bd502019-03-06 05:03:22 -060033
34namespace responder
35{
36
37namespace utils
38{
39
40void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
41 uint8_t& hours, uint8_t& day, uint8_t& month,
42 uint16_t& year)
43{
44 auto t = time_t(timeSec);
45 auto time = localtime(&t);
46
47 seconds = decimalToBcd(time->tm_sec);
48 minutes = decimalToBcd(time->tm_min);
49 hours = decimalToBcd(time->tm_hour);
50 day = decimalToBcd(time->tm_mday);
51 month =
52 decimalToBcd(time->tm_mon + 1); // The number of months in the range
53 // 0 to 11.PLDM expects range 1 to 12
54 year = decimalToBcd(time->tm_year + 1900); // The number of years since 1900
55}
56
John Wangc2938352019-09-30 13:58:41 +080057size_t getTableTotalsize(size_t sizeWithoutPad)
58{
John Wang79c37f12019-10-31 15:46:31 +080059 return sizeWithoutPad + pldm_bios_table_pad_checksum_size(sizeWithoutPad);
John Wangc2938352019-09-30 13:58:41 +080060}
61
62void padAndChecksum(Table& table)
63{
John Wang79c37f12019-10-31 15:46:31 +080064 auto sizeWithoutPad = table.size();
65 auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad);
66 table.resize(table.size() + padAndChecksumSize);
John Wangc2938352019-09-30 13:58:41 +080067
John Wang79c37f12019-10-31 15:46:31 +080068 pldm_bios_table_append_pad_checksum(table.data(), table.size(),
69 sizeWithoutPad);
John Wangc2938352019-09-30 13:58:41 +080070}
71
Sampa Misra032bd502019-03-06 05:03:22 -060072} // namespace utils
73
Deepak Kodihallibc669f12019-11-28 08:52:07 -060074namespace bios
75{
76
77Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -060078{
79 uint8_t seconds = 0;
80 uint8_t minutes = 0;
81 uint8_t hours = 0;
82 uint8_t day = 0;
83 uint8_t month = 0;
84 uint16_t year = 0;
85
86 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liu408c3c42019-10-16 16:49:15 +080087 constexpr auto hostTimePath = "/xyz/openbmc_project/time/host";
vkaverapa6575b82019-04-03 05:33:52 -050088 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
89 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misra032bd502019-03-06 05:03:22 -060090 std::variant<EpochTimeUS> value;
91
92 auto bus = sdbusplus::bus::new_default();
93 try
94 {
George Liu408c3c42019-10-16 16:49:15 +080095 auto service = getService(bus, hostTimePath, timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -060096
George Liu408c3c42019-10-16 16:49:15 +080097 auto method = bus.new_method_call(service.c_str(), hostTimePath,
Sampa Misra032bd502019-03-06 05:03:22 -060098 dbusProperties, "Get");
99 method.append(timeInterface, "Elapsed");
100
101 auto reply = bus.call(method);
102 reply.read(value);
103 }
104
105 catch (std::exception& e)
106 {
George Liu408c3c42019-10-16 16:49:15 +0800107 log<level::ERR>("Error getting time", entry("PATH=%s", hostTimePath),
Sampa Misra032bd502019-03-06 05:03:22 -0600108 entry("TIME INTERACE=%s", timeInterface));
109
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530110 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
111 minutes, hours, day, month, year,
112 responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500113 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600114 }
115
116 uint64_t timeUsec = std::get<EpochTimeUS>(value);
117
118 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
119 std::chrono::microseconds(timeUsec))
120 .count();
121
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600122 pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours,
123 day, month, year);
Sampa Misra032bd502019-03-06 05:03:22 -0600124
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530125 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
126 minutes, hours, day, month, year, responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500127 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600128}
129
Sampa Misrab37be312019-07-03 02:26:41 -0500130/** @brief Construct the BIOS string table
131 *
132 * @param[in] BIOSStringTable - the string table
133 * @param[in] transferHandle - transfer handle to identify part of transfer
134 * @param[in] transferOpFlag - flag to indicate which part of data being
135 * transferred
136 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500137 */
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500138Response getBIOSStringTable(BIOSTable& BIOSStringTable,
139 uint32_t /*transferHandle*/,
John Wange96e7e52019-10-05 17:47:30 +0800140 uint8_t /*transferOpFlag*/, uint8_t instanceID)
141
Sampa Misrab37be312019-07-03 02:26:41 -0500142{
143 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
144 0);
145 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
John Wangdd9a6282019-10-11 18:52:46 +0800146 if (!BIOSStringTable.isEmpty())
147 {
148 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS,
149 0, /* next transfer handle */
150 PLDM_START_AND_END, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500151 responsePtr); // filling up the header here
152 BIOSStringTable.load(response);
John Wangdd9a6282019-10-11 18:52:46 +0800153 return response;
154 }
155 auto biosStrings = bios_parser::getStrings();
156 std::sort(biosStrings.begin(), biosStrings.end());
157 // remove all duplicate strings received from bios json
158 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
159 biosStrings.end());
160
161 size_t sizeWithoutPad = std::accumulate(
162 biosStrings.begin(), biosStrings.end(), 0,
163 [](size_t sum, const std::string& elem) {
164 return sum +
165 pldm_bios_table_string_entry_encode_length(elem.length());
166 });
167
168 Table stringTable;
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600169 stringTable.reserve(
170 pldm::responder::utils::getTableTotalsize(sizeWithoutPad));
John Wangdd9a6282019-10-11 18:52:46 +0800171
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
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600184 pldm::responder::utils::padAndChecksum(stringTable);
John Wangdd9a6282019-10-11 18:52:46 +0800185 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 Wangdbbc9ff2019-10-25 13:53:46 +0800507namespace bios_type_integer
508{
509
510using namespace bios_parser::bios_integer;
511
512/** @brief Construct the attibute table for BIOS type Integer and
513 * Integer ReadOnly
514 * @param[in] BIOSStringTable - the string table
515 * @param[in,out] attributeTable - the attribute table
516 *
517 */
518void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
519{
520 const auto& attributeMap = getValues();
521 StringHandle strHandle;
522 for (const auto& [key, value] : attributeMap)
523 {
524 try
525 {
526 strHandle = findStringHandle(key, BIOSStringTable);
527 }
528 catch (InternalFailure& e)
529 {
530 log<level::ERR>("Could not find handle for BIOS string",
531 entry("ATTRIBUTE=%s", key.c_str()));
532 continue;
533 }
534
535 const auto& [readOnly, lowerBound, upperBound, scalarIncrement,
536 defaultValue] = value;
537 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
538
539 struct pldm_bios_table_attr_entry_integer_info info = {
540 strHandle, readOnly, lowerBound,
541 upperBound, scalarIncrement, defaultValue,
542 };
543 auto attrTableSize = attributeTable.size();
544 attributeTable.resize(attrTableSize + entryLength, 0);
545 pldm_bios_table_attr_entry_integer_encode(
546 attributeTable.data() + attrTableSize, entryLength, &info);
547 }
548}
549
550void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
551 const std::string& attrName,
552 const BIOSTable& BIOSStringTable,
553 Table& attrValueTable)
554{
555 std::ignore = BIOSStringTable;
556 uint64_t currentValue;
557 try
558 {
559 currentValue = getAttrValue(attrName);
560 }
561 catch (const std::exception& e)
562 {
563 log<level::ERR>("Failed to get attribute value",
564 entry("NAME=%s", attrName.c_str()),
565 entry("ERROR=%s", e.what()));
566 return;
567 }
568 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
569 auto tableSize = attrValueTable.size();
570 attrValueTable.resize(tableSize + entryLength);
571 pldm_bios_table_attr_value_entry_encode_integer(
572 attrValueTable.data() + tableSize, entryLength,
573 attrTableEntry->attr_handle, attrTableEntry->attr_type, currentValue);
574}
575
576} // namespace bios_type_integer
577
John Wang02700402019-10-06 16:34:29 +0800578void traverseBIOSAttrTable(const Table& biosAttrTable,
579 AttrTableEntryHandler handler)
580{
581 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
582 iter(pldm_bios_table_iter_create(biosAttrTable.data(),
583 biosAttrTable.size(),
584 PLDM_BIOS_ATTR_TABLE),
585 pldm_bios_table_iter_free);
586 while (!pldm_bios_table_iter_is_end(iter.get()))
587 {
588 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
589 try
590 {
591 handler(table_entry);
592 }
593 catch (const std::exception& e)
594 {
595 log<level::ERR>("handler fails when traversing BIOSAttrTable",
596 entry("ERROR=%s", e.what()));
597 }
598 pldm_bios_table_iter_next(iter.get());
599 }
600}
601
John Wange96e7e52019-10-05 17:47:30 +0800602using typeHandler = std::function<void(const BIOSTable& BIOSStringTable,
603 Table& attributeTable)>;
Carol Wangdc220c82019-08-26 13:31:31 +0800604std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
605 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
John Wangdbbc9ff2019-10-25 13:53:46 +0800606 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable},
607 {bios_parser::bIOSIntegerJson, bios_type_integer::constructAttrTable},
608};
Carol Wangdc220c82019-08-26 13:31:31 +0800609
Sampa Misrab37be312019-07-03 02:26:41 -0500610/** @brief Construct the BIOS attribute table
611 *
612 * @param[in] BIOSAttributeTable - the attribute table
613 * @param[in] BIOSStringTable - the string table
614 * @param[in] transferHandle - transfer handle to identify part of transfer
615 * @param[in] transferOpFlag - flag to indicate which part of data being
616 * transferred
617 * @param[in] instanceID - instance ID to identify the command
618 * @param[in] biosJsonDir - path where the BIOS json files are present
619 */
620Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
621 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500622 uint32_t /*transferHandle*/,
623 uint8_t /*transferOpFlag*/, uint8_t instanceID,
624 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500625{
626 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
627 0);
628 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
629 uint32_t nxtTransferHandle = 0;
630 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500631
632 if (BIOSAttributeTable.isEmpty())
633 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800634 Table attributeTable;
635 fs::path dir(biosJsonDir);
636
637 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
638 it++)
639 {
640 fs::path file = dir / it->first;
641 if (fs::exists(file))
642 {
John Wange96e7e52019-10-05 17:47:30 +0800643 it->second(BIOSStringTable, attributeTable);
Carol Wangdc220c82019-08-26 13:31:31 +0800644 }
645 }
646
647 if (attributeTable.empty())
648 { // no available json file is found
649 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
650 nxtTransferHandle, transferFlag, nullptr,
651 response.size(), responsePtr);
652 return response;
653 }
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600654 pldm::responder::utils::padAndChecksum(attributeTable);
John Wangc2938352019-09-30 13:58:41 +0800655 BIOSAttributeTable.store(attributeTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500656 response.resize(sizeof(pldm_msg_hdr) +
657 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
658 attributeTable.size());
659 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500660 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
661 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800662 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500663 }
664 else
665 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500666 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800667 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500668 responsePtr); // filling up the header here
669 BIOSAttributeTable.load(response);
670 }
671
672 return response;
673}
674
John Wang3ad21752019-10-06 16:42:21 +0800675using AttrValTableEntryConstructHandler =
676 std::function<void(const struct pldm_bios_attr_table_entry* tableEntry,
677 const std::string& attrName,
678 const BIOSTable& BIOSStringTable, Table& table)>;
679
680using AttrType = uint8_t;
681const std::map<AttrType, AttrValTableEntryConstructHandler>
682 AttrValTableConstructMap{
683 {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry},
684 {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry},
685 {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry},
686 {PLDM_BIOS_ENUMERATION_READ_ONLY,
687 bios_type_enum::constructAttrValueEntry},
John Wangdbbc9ff2019-10-25 13:53:46 +0800688 {PLDM_BIOS_INTEGER, bios_type_integer::constructAttrValueEntry},
689 {PLDM_BIOS_INTEGER_READ_ONLY,
690 bios_type_integer::constructAttrValueEntry},
John Wang3ad21752019-10-06 16:42:21 +0800691 };
692
693void constructAttrValueTableEntry(
694 const struct pldm_bios_attr_table_entry* attrEntry,
695 const BIOSTable& BIOSStringTable, Table& attributeValueTable)
696{
697 auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable);
698 if (attrName.empty())
699 {
700 log<level::ERR>("invalid string handle",
701 entry("STRING_HANDLE=%d", attrEntry->string_handle));
702 return;
703 }
704
705 AttrValTableConstructMap.at(attrEntry->attr_type)(
706 attrEntry, attrName, BIOSStringTable, attributeValueTable);
707}
708
Sampa Misrab37be312019-07-03 02:26:41 -0500709/** @brief Construct the BIOS attribute value table
710 *
711 * @param[in] BIOSAttributeValueTable - the attribute value table
712 * @param[in] BIOSAttributeTable - the attribute table
713 * @param[in] BIOSStringTable - the string table
714 * @param[in] transferHandle - transfer handle to identify part of transfer
715 * @param[in] transferOpFlag - flag to indicate which part of data being
716 * transferred
717 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500718 */
719Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
720 const BIOSTable& BIOSAttributeTable,
721 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500722 uint32_t& /*transferHandle*/,
723 uint8_t& /*transferOpFlag*/,
John Wang3ad21752019-10-06 16:42:21 +0800724 uint8_t instanceID)
Sampa Misrab37be312019-07-03 02:26:41 -0500725{
726 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
727 0);
728 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
729 uint32_t nxtTransferHandle = 0;
730 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500731
John Wang3ad21752019-10-06 16:42:21 +0800732 if (!BIOSAttributeValueTable.isEmpty())
733 {
Sampa Misrab37be312019-07-03 02:26:41 -0500734 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
John Wang3ad21752019-10-06 16:42:21 +0800735 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500736 responsePtr); // filling up the header here
737 BIOSAttributeValueTable.load(response);
John Wang3ad21752019-10-06 16:42:21 +0800738 return response;
Sampa Misrab37be312019-07-03 02:26:41 -0500739 }
740
John Wang3ad21752019-10-06 16:42:21 +0800741 Table attributeValueTable;
742 Table attributeTable;
743 BIOSAttributeTable.load(attributeTable);
744 traverseBIOSAttrTable(
745 attributeTable,
746 [&BIOSStringTable, &attributeValueTable](
747 const struct pldm_bios_attr_table_entry* tableEntry) {
748 constructAttrValueTableEntry(tableEntry, BIOSStringTable,
749 attributeValueTable);
750 });
751 if (attributeValueTable.empty())
752 {
753 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
754 nxtTransferHandle, transferFlag, nullptr,
755 response.size(), responsePtr);
756 return response;
757 }
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600758 pldm::responder::utils::padAndChecksum(attributeValueTable);
John Wang3ad21752019-10-06 16:42:21 +0800759 BIOSAttributeValueTable.store(attributeValueTable);
760
761 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
762 attributeValueTable.size());
763 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
764 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
765 transferFlag, attributeValueTable.data(),
766 response.size(), responsePtr);
767
Sampa Misrab37be312019-07-03 02:26:41 -0500768 return response;
769}
770
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600771Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength)
Sampa Misrab37be312019-07-03 02:26:41 -0500772{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500773 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500774 auto response = internal::buildBIOSTables(request, payloadLength,
775 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
776
777 return response;
778}
779
Sampa Misrab37be312019-07-03 02:26:41 -0500780namespace internal
781{
782
783Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
784 const char* biosJsonDir, const char* biosTablePath)
785{
786 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
787 0);
788 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
789
John Wange96e7e52019-10-05 17:47:30 +0800790 if (setupConfig(biosJsonDir) != 0)
791 {
792 encode_get_bios_table_resp(
793 request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE,
794 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr,
795 response.size(), responsePtr);
796 return response;
797 }
798
Sampa Misrab37be312019-07-03 02:26:41 -0500799 uint32_t transferHandle{};
800 uint8_t transferOpFlag{};
801 uint8_t tableType{};
802
803 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
804 &transferOpFlag, &tableType);
805 if (rc == PLDM_SUCCESS)
806 {
807 BIOSTable BIOSStringTable(
808 ((std::string(biosTablePath) + "/stringTable")).c_str());
809 BIOSTable BIOSAttributeTable(
810 ((std::string(biosTablePath) + "/attributeTable")).c_str());
811 BIOSTable BIOSAttributeValueTable(
812 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
813 switch (tableType)
814 {
815 case PLDM_BIOS_STRING_TABLE:
816
John Wange96e7e52019-10-05 17:47:30 +0800817 response = getBIOSStringTable(BIOSStringTable, transferHandle,
818 transferOpFlag,
819 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500820 break;
821 case PLDM_BIOS_ATTR_TABLE:
822
823 if (BIOSStringTable.isEmpty())
824 {
825 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
826 }
827 else
828 {
829 response = getBIOSAttributeTable(
830 BIOSAttributeTable, BIOSStringTable, transferHandle,
831 transferOpFlag, request->hdr.instance_id, biosJsonDir);
832 }
833 break;
834 case PLDM_BIOS_ATTR_VAL_TABLE:
Carol Wangf7d1a362019-11-18 15:34:14 +0800835 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty())
Sampa Misrab37be312019-07-03 02:26:41 -0500836 {
837 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
838 }
839 else
840 {
841 response = getBIOSAttributeValueTable(
842 BIOSAttributeValueTable, BIOSAttributeTable,
843 BIOSStringTable, transferHandle, transferOpFlag,
John Wang3ad21752019-10-06 16:42:21 +0800844 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500845 }
846 break;
847 default:
848 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
849 break;
850 }
851 }
852
853 if (rc != PLDM_SUCCESS)
854 {
855 uint32_t nxtTransferHandle{};
856 uint8_t transferFlag{};
857 size_t respPayloadLength{};
858
859 encode_get_bios_table_resp(request->hdr.instance_id, rc,
860 nxtTransferHandle, transferFlag, nullptr,
861 respPayloadLength, responsePtr);
862 }
863
864 return response;
865}
866
867} // end namespace internal
868} // namespace bios
869
Sampa Misra032bd502019-03-06 05:03:22 -0600870} // namespace responder
871} // namespace pldm