blob: 47bfc0aae4426f721166502315391a351a003076 [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 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 }
John Wangc2938352019-09-30 13:58:41 +0800654 utils::padAndChecksum(attributeTable);
655 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 }
758 utils::padAndChecksum(attributeValueTable);
759 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
771Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
772{
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
780namespace bios
781{
782
783void registerHandlers()
784{
785 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
786 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
787}
788
789namespace internal
790{
791
792Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
793 const char* biosJsonDir, const char* biosTablePath)
794{
795 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
796 0);
797 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
798
John Wange96e7e52019-10-05 17:47:30 +0800799 if (setupConfig(biosJsonDir) != 0)
800 {
801 encode_get_bios_table_resp(
802 request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE,
803 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr,
804 response.size(), responsePtr);
805 return response;
806 }
807
Sampa Misrab37be312019-07-03 02:26:41 -0500808 uint32_t transferHandle{};
809 uint8_t transferOpFlag{};
810 uint8_t tableType{};
811
812 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
813 &transferOpFlag, &tableType);
814 if (rc == PLDM_SUCCESS)
815 {
816 BIOSTable BIOSStringTable(
817 ((std::string(biosTablePath) + "/stringTable")).c_str());
818 BIOSTable BIOSAttributeTable(
819 ((std::string(biosTablePath) + "/attributeTable")).c_str());
820 BIOSTable BIOSAttributeValueTable(
821 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
822 switch (tableType)
823 {
824 case PLDM_BIOS_STRING_TABLE:
825
John Wange96e7e52019-10-05 17:47:30 +0800826 response = getBIOSStringTable(BIOSStringTable, transferHandle,
827 transferOpFlag,
828 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500829 break;
830 case PLDM_BIOS_ATTR_TABLE:
831
832 if (BIOSStringTable.isEmpty())
833 {
834 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
835 }
836 else
837 {
838 response = getBIOSAttributeTable(
839 BIOSAttributeTable, BIOSStringTable, transferHandle,
840 transferOpFlag, request->hdr.instance_id, biosJsonDir);
841 }
842 break;
843 case PLDM_BIOS_ATTR_VAL_TABLE:
Carol Wangf7d1a362019-11-18 15:34:14 +0800844 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty())
Sampa Misrab37be312019-07-03 02:26:41 -0500845 {
846 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
847 }
848 else
849 {
850 response = getBIOSAttributeValueTable(
851 BIOSAttributeValueTable, BIOSAttributeTable,
852 BIOSStringTable, transferHandle, transferOpFlag,
John Wang3ad21752019-10-06 16:42:21 +0800853 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500854 }
855 break;
856 default:
857 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
858 break;
859 }
860 }
861
862 if (rc != PLDM_SUCCESS)
863 {
864 uint32_t nxtTransferHandle{};
865 uint8_t transferFlag{};
866 size_t respPayloadLength{};
867
868 encode_get_bios_table_resp(request->hdr.instance_id, rc,
869 nxtTransferHandle, transferFlag, nullptr,
870 respPayloadLength, responsePtr);
871 }
872
873 return response;
874}
875
876} // end namespace internal
877} // namespace bios
878
Sampa Misra032bd502019-03-06 05:03:22 -0600879} // namespace responder
880} // namespace pldm