blob: 1c48f1a1e8935ef791fef840971f41becaeb3afa [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{
John Wang79c37f12019-10-31 15:46:31 +080060 return sizeWithoutPad + pldm_bios_table_pad_checksum_size(sizeWithoutPad);
John Wangc2938352019-09-30 13:58:41 +080061}
62
63void padAndChecksum(Table& table)
64{
John Wang79c37f12019-10-31 15:46:31 +080065 auto sizeWithoutPad = table.size();
66 auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad);
67 table.resize(table.size() + padAndChecksumSize);
John Wangc2938352019-09-30 13:58:41 +080068
John Wang79c37f12019-10-31 15:46:31 +080069 pldm_bios_table_append_pad_checksum(table.data(), table.size(),
70 sizeWithoutPad);
John Wangc2938352019-09-30 13:58:41 +080071}
72
Sampa Misra032bd502019-03-06 05:03:22 -060073} // namespace utils
74
Deepak Kodihalli3c275e12019-09-21 06:39:39 -050075Response getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -060076{
77 uint8_t seconds = 0;
78 uint8_t minutes = 0;
79 uint8_t hours = 0;
80 uint8_t day = 0;
81 uint8_t month = 0;
82 uint16_t year = 0;
83
84 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liu408c3c42019-10-16 16:49:15 +080085 constexpr auto hostTimePath = "/xyz/openbmc_project/time/host";
vkaverapa6575b82019-04-03 05:33:52 -050086 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
87 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misra032bd502019-03-06 05:03:22 -060088 std::variant<EpochTimeUS> value;
89
90 auto bus = sdbusplus::bus::new_default();
91 try
92 {
George Liu408c3c42019-10-16 16:49:15 +080093 auto service = getService(bus, hostTimePath, timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -060094
George Liu408c3c42019-10-16 16:49:15 +080095 auto method = bus.new_method_call(service.c_str(), hostTimePath,
Sampa Misra032bd502019-03-06 05:03:22 -060096 dbusProperties, "Get");
97 method.append(timeInterface, "Elapsed");
98
99 auto reply = bus.call(method);
100 reply.read(value);
101 }
102
103 catch (std::exception& e)
104 {
George Liu408c3c42019-10-16 16:49:15 +0800105 log<level::ERR>("Error getting time", entry("PATH=%s", hostTimePath),
Sampa Misra032bd502019-03-06 05:03:22 -0600106 entry("TIME INTERACE=%s", timeInterface));
107
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530108 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
109 minutes, hours, day, month, year,
110 responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500111 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600112 }
113
114 uint64_t timeUsec = std::get<EpochTimeUS>(value);
115
116 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
117 std::chrono::microseconds(timeUsec))
118 .count();
119
120 utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
121
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530122 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
123 minutes, hours, day, month, year, responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500124 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600125}
126
Sampa Misrab37be312019-07-03 02:26:41 -0500127/** @brief Construct the BIOS string table
128 *
129 * @param[in] BIOSStringTable - the string table
130 * @param[in] transferHandle - transfer handle to identify part of transfer
131 * @param[in] transferOpFlag - flag to indicate which part of data being
132 * transferred
133 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500134 */
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500135Response getBIOSStringTable(BIOSTable& BIOSStringTable,
136 uint32_t /*transferHandle*/,
John Wange96e7e52019-10-05 17:47:30 +0800137 uint8_t /*transferOpFlag*/, uint8_t instanceID)
138
Sampa Misrab37be312019-07-03 02:26:41 -0500139{
140 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
141 0);
142 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
John Wangdd9a6282019-10-11 18:52:46 +0800143 if (!BIOSStringTable.isEmpty())
144 {
145 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS,
146 0, /* next transfer handle */
147 PLDM_START_AND_END, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500148 responsePtr); // filling up the header here
149 BIOSStringTable.load(response);
John Wangdd9a6282019-10-11 18:52:46 +0800150 return response;
151 }
152 auto biosStrings = bios_parser::getStrings();
153 std::sort(biosStrings.begin(), biosStrings.end());
154 // remove all duplicate strings received from bios json
155 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
156 biosStrings.end());
157
158 size_t sizeWithoutPad = std::accumulate(
159 biosStrings.begin(), biosStrings.end(), 0,
160 [](size_t sum, const std::string& elem) {
161 return sum +
162 pldm_bios_table_string_entry_encode_length(elem.length());
163 });
164
165 Table stringTable;
166 stringTable.reserve(utils::getTableTotalsize(sizeWithoutPad));
167
168 stringTable.resize(sizeWithoutPad);
169 auto tablePtr = stringTable.data();
170 for (const auto& elem : biosStrings)
171 {
172 auto entry_length =
173 pldm_bios_table_string_entry_encode_length(elem.length());
174 pldm_bios_table_string_entry_encode(tablePtr, sizeWithoutPad,
175 elem.c_str(), elem.length());
176 tablePtr += entry_length;
177 sizeWithoutPad -= entry_length;
Sampa Misrab37be312019-07-03 02:26:41 -0500178 }
179
John Wangdd9a6282019-10-11 18:52:46 +0800180 utils::padAndChecksum(stringTable);
181 BIOSStringTable.store(stringTable);
182 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
183 stringTable.size(),
184 0);
185 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
186 encode_get_bios_table_resp(
187 instanceID, PLDM_SUCCESS, 0 /* nxtTransferHandle */, PLDM_START_AND_END,
188 stringTable.data(), response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500189 return response;
190}
191
192/** @brief Find the string handle from the BIOS string table given the name
193 *
194 * @param[in] name - name of the BIOS string
195 * @param[in] BIOSStringTable - the string table
196 * @return - uint16_t - handle of the string
197 */
198StringHandle findStringHandle(const std::string& name,
199 const BIOSTable& BIOSStringTable)
200{
John Wangdd9a6282019-10-11 18:52:46 +0800201 Table table;
202 BIOSStringTable.load(table);
203 auto stringEntry = pldm_bios_table_string_find_by_string(
204 table.data(), table.size(), name.c_str());
205 if (stringEntry == nullptr)
Sampa Misrab37be312019-07-03 02:26:41 -0500206 {
John Wangdd9a6282019-10-11 18:52:46 +0800207 log<level::ERR>("Reached end of BIOS string table,did not find the "
208 "handle for the string",
209 entry("STRING=%s", name.c_str()));
210 elog<InternalFailure>();
Sampa Misrab37be312019-07-03 02:26:41 -0500211 }
John Wangdd9a6282019-10-11 18:52:46 +0800212
213 return pldm_bios_table_string_entry_decode_handle(stringEntry);
Sampa Misrab37be312019-07-03 02:26:41 -0500214}
215
216/** @brief Find the string name from the BIOS string table for a string handle
217 *
218 * @param[in] stringHdl - string handle
219 * @param[in] BIOSStringTable - the string table
220 *
221 * @return - std::string - name of the corresponding BIOS string
222 */
223std::string findStringName(StringHandle stringHdl,
224 const BIOSTable& BIOSStringTable)
225{
John Wangdd9a6282019-10-11 18:52:46 +0800226 Table table;
227 BIOSStringTable.load(table);
228 auto stringEntry = pldm_bios_table_string_find_by_handle(
229 table.data(), table.size(), stringHdl);
Sampa Misrab37be312019-07-03 02:26:41 -0500230 std::string name;
John Wangdd9a6282019-10-11 18:52:46 +0800231 if (stringEntry == nullptr)
Sampa Misrab37be312019-07-03 02:26:41 -0500232 {
John Wangdd9a6282019-10-11 18:52:46 +0800233 log<level::ERR>("Reached end of BIOS string table,did not find "
234 "string name for handle",
235 entry("STRING_HANDLE=%d", stringHdl));
Sampa Misrab37be312019-07-03 02:26:41 -0500236 }
John Wangdd9a6282019-10-11 18:52:46 +0800237 auto strLength =
238 pldm_bios_table_string_entry_decode_string_length(stringEntry);
239 name.resize(strLength);
240 pldm_bios_table_string_entry_decode_string(stringEntry, name.data(),
241 name.size());
Sampa Misrab37be312019-07-03 02:26:41 -0500242 return name;
243}
244
245namespace bios_type_enum
246{
247
Carol Wangdc220c82019-08-26 13:31:31 +0800248using namespace bios_parser::bios_enum;
249
Sampa Misrab37be312019-07-03 02:26:41 -0500250/** @brief Find the indices into the array of the possible values of string
251 * handles for the current values.This is used in attribute value table
252 *
253 * @param[in] possiVals - vector of string handles comprising all the possible
254 * values for an attribute
255 * @param[in] currVals - vector of strings comprising all current values
256 * for an attribute
257 * @param[in] BIOSStringTable - the string table
258 *
259 * @return - std::vector<uint8_t> - indices into the array of the possible
260 * values of string handles
261 */
262std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
263 CurrentValues currVals,
264 const BIOSTable& BIOSStringTable)
265{
266 std::vector<uint8_t> stringIndices;
267
268 for (const auto& currVal : currVals)
269 {
270 StringHandle curHdl;
271 try
272 {
273 curHdl = findStringHandle(currVal, BIOSStringTable);
274 }
275 catch (InternalFailure& e)
276 {
277 log<level::ERR>("Exception fetching handle for the string",
278 entry("STRING=%s", currVal.c_str()));
279 continue;
280 }
281
282 uint8_t i = 0;
283 for (auto possiHdl : possiVals)
284 {
285 if (possiHdl == curHdl)
286 {
287 stringIndices.push_back(i);
288 break;
289 }
290 i++;
291 }
292 }
293 return stringIndices;
294}
295
296/** @brief Find the indices into the array of the possible values of string
297 * handles for the default values. This is used in attribute table
298 *
299 * @param[in] possiVals - vector of strings comprising all the possible values
300 * for an attribute
301 * @param[in] defVals - vector of strings comprising all the default values
302 * for an attribute
303 * @return - std::vector<uint8_t> - indices into the array of the possible
304 * values of string
305 */
306std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
307 const DefaultValues& defVals)
308{
309 std::vector<uint8_t> defHdls;
310 for (const auto& defs : defVals)
311 {
312 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
313 if (index != possiVals.end())
314 {
315 defHdls.push_back(index - possiVals.begin());
316 }
317 }
318
319 return defHdls;
320}
321
322/** @brief Construct the attibute table for BIOS type Enumeration and
323 * Enumeration ReadOnly
324 * @param[in] BIOSStringTable - the string table
325 * @param[in] biosJsonDir - path where the BIOS json files are present
Carol Wangdc220c82019-08-26 13:31:31 +0800326 * @param[in,out] attributeTable - the attribute table
Sampa Misrab37be312019-07-03 02:26:41 -0500327 *
Sampa Misrab37be312019-07-03 02:26:41 -0500328 */
John Wange96e7e52019-10-05 17:47:30 +0800329void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500330{
Sampa Misrab37be312019-07-03 02:26:41 -0500331 const auto& attributeMap = getValues();
Sampa Misrab37be312019-07-03 02:26:41 -0500332 StringHandle strHandle;
333
334 for (const auto& [key, value] : attributeMap)
335 {
336 try
337 {
338 strHandle = findStringHandle(key, BIOSStringTable);
339 }
340 catch (InternalFailure& e)
341 {
342 log<level::ERR>("Could not find handle for BIOS string",
343 entry("ATTRIBUTE=%s", key.c_str()));
344 continue;
345 }
John Wangccc04552019-10-14 14:28:25 +0800346 bool readOnly = (std::get<0>(value));
Sampa Misrab37be312019-07-03 02:26:41 -0500347 PossibleValues possiVals = std::get<1>(value);
348 DefaultValues defVals = std::get<2>(value);
349 // both the possible and default values are stored in sorted manner to
350 // ease in fetching back/comparison
351 std::sort(possiVals.begin(), possiVals.end());
352 std::sort(defVals.begin(), defVals.end());
353
354 std::vector<StringHandle> possiValsByHdl;
355 for (const auto& elem : possiVals)
356 {
357 try
358 {
359 auto hdl = findStringHandle(elem, BIOSStringTable);
360 possiValsByHdl.push_back(std::move(hdl));
361 }
362 catch (InternalFailure& e)
363 {
364 log<level::ERR>("Could not find handle for BIOS string",
365 entry("STRING=%s", elem.c_str()));
366 continue;
367 }
368 }
369 auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
John Wangccc04552019-10-14 14:28:25 +0800370 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
371 possiValsByHdl.size(), defValsByHdl.size());
Sampa Misrab37be312019-07-03 02:26:41 -0500372
John Wangccc04552019-10-14 14:28:25 +0800373 auto attrTableSize = attributeTable.size();
374 attributeTable.resize(attrTableSize + entryLength, 0);
375 struct pldm_bios_table_attr_entry_enum_info info = {
376 strHandle,
377 readOnly,
378 (uint8_t)possiValsByHdl.size(),
379 possiValsByHdl.data(),
380 (uint8_t)defValsByHdl.size(),
381 defValsByHdl.data(),
382 };
383 pldm_bios_table_attr_entry_enum_encode(
384 attributeTable.data() + attrTableSize, entryLength, &info);
Sampa Misrab37be312019-07-03 02:26:41 -0500385 }
Sampa Misrab37be312019-07-03 02:26:41 -0500386}
387
John Wang3ad21752019-10-06 16:42:21 +0800388void constructAttrValueEntry(
389 const struct pldm_bios_attr_table_entry* attrTableEntry,
390 const std::string& attrName, const BIOSTable& BIOSStringTable,
391 Table& attrValueTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500392{
John Wang3ad21752019-10-06 16:42:21 +0800393 CurrentValues currVals;
394 try
Sampa Misrab37be312019-07-03 02:26:41 -0500395 {
John Wang3ad21752019-10-06 16:42:21 +0800396 currVals = getAttrValue(attrName);
Sampa Misrab37be312019-07-03 02:26:41 -0500397 }
John Wang3ad21752019-10-06 16:42:21 +0800398 catch (const std::exception& e)
399 {
400 log<level::ERR>("getAttrValue returned error for attribute",
401 entry("NAME=%s", attrName.c_str()),
402 entry("ERROR=%s", e.what()));
403 return;
404 }
405 uint8_t pv_num =
406 pldm_bios_table_attr_entry_enum_decode_pv_num(attrTableEntry);
407 PossibleValuesByHandle pvHdls(pv_num, 0);
408 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrTableEntry,
409 pvHdls.data(), pv_num);
410 std::sort(currVals.begin(), currVals.end());
411
412 auto currValStrIndices = findStrIndices(pvHdls, currVals, BIOSStringTable);
413
414 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
415 currValStrIndices.size());
416 auto tableSize = attrValueTable.size();
417 attrValueTable.resize(tableSize + entryLength);
418 pldm_bios_table_attr_value_entry_encode_enum(
419 attrValueTable.data() + tableSize, entryLength,
420 attrTableEntry->attr_handle, attrTableEntry->attr_type,
421 currValStrIndices.size(), currValStrIndices.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500422}
423
424} // end namespace bios_type_enum
425
Carol Wangdc220c82019-08-26 13:31:31 +0800426namespace bios_type_string
427{
Carol Wang612f35b2019-08-26 17:14:26 +0800428
429using namespace bios_parser::bios_string;
430
Carol Wangdc220c82019-08-26 13:31:31 +0800431/** @brief Construct the attibute table for BIOS type String and
432 * String ReadOnly
433 * @param[in] BIOSStringTable - the string table
434 * @param[in] biosJsonDir - path where the BIOS json files are present
435 * @param[in,out] attributeTable - the attribute table
436 *
437 */
John Wange96e7e52019-10-05 17:47:30 +0800438void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800439{
Carol Wang612f35b2019-08-26 17:14:26 +0800440 const auto& attributeMap = getValues();
441 StringHandle strHandle;
Carol Wang612f35b2019-08-26 17:14:26 +0800442 for (const auto& [key, value] : attributeMap)
443 {
444 try
445 {
446 strHandle = findStringHandle(key, BIOSStringTable);
447 }
448 catch (InternalFailure& e)
449 {
450 log<level::ERR>("Could not find handle for BIOS string",
451 entry("ATTRIBUTE=%s", key.c_str()));
452 continue;
453 }
454
John Wangccc04552019-10-14 14:28:25 +0800455 const auto& [readOnly, strType, minStrLen, maxStrLen, defaultStrLen,
Carol Wang612f35b2019-08-26 17:14:26 +0800456 defaultStr] = value;
John Wangccc04552019-10-14 14:28:25 +0800457 auto entryLength =
458 pldm_bios_table_attr_entry_string_encode_length(defaultStrLen);
Carol Wang612f35b2019-08-26 17:14:26 +0800459
John Wangccc04552019-10-14 14:28:25 +0800460 struct pldm_bios_table_attr_entry_string_info info = {
461 strHandle, readOnly, strType, minStrLen,
462 maxStrLen, defaultStrLen, defaultStr.data(),
463 };
464 auto attrTableSize = attributeTable.size();
465 attributeTable.resize(attrTableSize + entryLength, 0);
466 pldm_bios_table_attr_entry_string_encode(
467 attributeTable.data() + attrTableSize, entryLength, &info);
Carol Wang612f35b2019-08-26 17:14:26 +0800468 }
Carol Wangdc220c82019-08-26 13:31:31 +0800469}
Carol Wangb503f9e2019-09-02 16:34:10 +0800470
John Wang3ad21752019-10-06 16:42:21 +0800471void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
472 const std::string& attrName,
Carol Wangb503f9e2019-09-02 16:34:10 +0800473 const BIOSTable& BIOSStringTable,
John Wang3ad21752019-10-06 16:42:21 +0800474 Table& attrValueTable)
Carol Wangb503f9e2019-09-02 16:34:10 +0800475{
John Wang3ad21752019-10-06 16:42:21 +0800476 std::ignore = BIOSStringTable;
477 std::string currStr;
478 uint16_t currStrLen = 0;
479 try
Carol Wangb503f9e2019-09-02 16:34:10 +0800480 {
John Wang3ad21752019-10-06 16:42:21 +0800481 currStr = getAttrValue(attrName);
482 currStrLen = currStr.size();
Carol Wangb503f9e2019-09-02 16:34:10 +0800483 }
John Wang3ad21752019-10-06 16:42:21 +0800484 catch (const std::exception& e)
485 {
486 log<level::ERR>("getAttrValue returned error for attribute",
487 entry("NAME=%s", attrName.c_str()),
488 entry("ERROR=%s", e.what()));
489 return;
490 }
491 auto entryLength =
492 pldm_bios_table_attr_value_entry_encode_string_length(currStrLen);
493 auto tableSize = attrValueTable.size();
494 attrValueTable.resize(tableSize + entryLength);
495 pldm_bios_table_attr_value_entry_encode_string(
496 attrValueTable.data() + tableSize, entryLength,
497 attrTableEntry->attr_handle, attrTableEntry->attr_type, currStrLen,
498 currStr.c_str());
Carol Wangb503f9e2019-09-02 16:34:10 +0800499}
500
Carol Wangdc220c82019-08-26 13:31:31 +0800501} // end namespace bios_type_string
502
John Wangdbbc9ff2019-10-25 13:53:46 +0800503namespace bios_type_integer
504{
505
506using namespace bios_parser::bios_integer;
507
508/** @brief Construct the attibute table for BIOS type Integer and
509 * Integer ReadOnly
510 * @param[in] BIOSStringTable - the string table
511 * @param[in,out] attributeTable - the attribute table
512 *
513 */
514void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
515{
516 const auto& attributeMap = getValues();
517 StringHandle strHandle;
518 for (const auto& [key, value] : attributeMap)
519 {
520 try
521 {
522 strHandle = findStringHandle(key, BIOSStringTable);
523 }
524 catch (InternalFailure& e)
525 {
526 log<level::ERR>("Could not find handle for BIOS string",
527 entry("ATTRIBUTE=%s", key.c_str()));
528 continue;
529 }
530
531 const auto& [readOnly, lowerBound, upperBound, scalarIncrement,
532 defaultValue] = value;
533 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
534
535 struct pldm_bios_table_attr_entry_integer_info info = {
536 strHandle, readOnly, lowerBound,
537 upperBound, scalarIncrement, defaultValue,
538 };
539 auto attrTableSize = attributeTable.size();
540 attributeTable.resize(attrTableSize + entryLength, 0);
541 pldm_bios_table_attr_entry_integer_encode(
542 attributeTable.data() + attrTableSize, entryLength, &info);
543 }
544}
545
546void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
547 const std::string& attrName,
548 const BIOSTable& BIOSStringTable,
549 Table& attrValueTable)
550{
551 std::ignore = BIOSStringTable;
552 uint64_t currentValue;
553 try
554 {
555 currentValue = getAttrValue(attrName);
556 }
557 catch (const std::exception& e)
558 {
559 log<level::ERR>("Failed to get attribute value",
560 entry("NAME=%s", attrName.c_str()),
561 entry("ERROR=%s", e.what()));
562 return;
563 }
564 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
565 auto tableSize = attrValueTable.size();
566 attrValueTable.resize(tableSize + entryLength);
567 pldm_bios_table_attr_value_entry_encode_integer(
568 attrValueTable.data() + tableSize, entryLength,
569 attrTableEntry->attr_handle, attrTableEntry->attr_type, currentValue);
570}
571
572} // namespace bios_type_integer
573
John Wang02700402019-10-06 16:34:29 +0800574void traverseBIOSAttrTable(const Table& biosAttrTable,
575 AttrTableEntryHandler handler)
576{
577 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
578 iter(pldm_bios_table_iter_create(biosAttrTable.data(),
579 biosAttrTable.size(),
580 PLDM_BIOS_ATTR_TABLE),
581 pldm_bios_table_iter_free);
582 while (!pldm_bios_table_iter_is_end(iter.get()))
583 {
584 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
585 try
586 {
587 handler(table_entry);
588 }
589 catch (const std::exception& e)
590 {
591 log<level::ERR>("handler fails when traversing BIOSAttrTable",
592 entry("ERROR=%s", e.what()));
593 }
594 pldm_bios_table_iter_next(iter.get());
595 }
596}
597
John Wange96e7e52019-10-05 17:47:30 +0800598using typeHandler = std::function<void(const BIOSTable& BIOSStringTable,
599 Table& attributeTable)>;
Carol Wangdc220c82019-08-26 13:31:31 +0800600std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
601 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
John Wangdbbc9ff2019-10-25 13:53:46 +0800602 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable},
603 {bios_parser::bIOSIntegerJson, bios_type_integer::constructAttrTable},
604};
Carol Wangdc220c82019-08-26 13:31:31 +0800605
Sampa Misrab37be312019-07-03 02:26:41 -0500606/** @brief Construct the BIOS attribute table
607 *
608 * @param[in] BIOSAttributeTable - the attribute table
609 * @param[in] BIOSStringTable - the string table
610 * @param[in] transferHandle - transfer handle to identify part of transfer
611 * @param[in] transferOpFlag - flag to indicate which part of data being
612 * transferred
613 * @param[in] instanceID - instance ID to identify the command
614 * @param[in] biosJsonDir - path where the BIOS json files are present
615 */
616Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
617 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500618 uint32_t /*transferHandle*/,
619 uint8_t /*transferOpFlag*/, uint8_t instanceID,
620 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500621{
622 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
623 0);
624 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
625 uint32_t nxtTransferHandle = 0;
626 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500627
628 if (BIOSAttributeTable.isEmpty())
629 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800630 Table attributeTable;
631 fs::path dir(biosJsonDir);
632
633 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
634 it++)
635 {
636 fs::path file = dir / it->first;
637 if (fs::exists(file))
638 {
John Wange96e7e52019-10-05 17:47:30 +0800639 it->second(BIOSStringTable, attributeTable);
Carol Wangdc220c82019-08-26 13:31:31 +0800640 }
641 }
642
643 if (attributeTable.empty())
644 { // no available json file is found
645 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
646 nxtTransferHandle, transferFlag, nullptr,
647 response.size(), responsePtr);
648 return response;
649 }
John Wangc2938352019-09-30 13:58:41 +0800650 utils::padAndChecksum(attributeTable);
651 BIOSAttributeTable.store(attributeTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500652 response.resize(sizeof(pldm_msg_hdr) +
653 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
654 attributeTable.size());
655 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500656 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
657 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800658 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500659 }
660 else
661 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500662 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800663 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500664 responsePtr); // filling up the header here
665 BIOSAttributeTable.load(response);
666 }
667
668 return response;
669}
670
John Wang3ad21752019-10-06 16:42:21 +0800671using AttrValTableEntryConstructHandler =
672 std::function<void(const struct pldm_bios_attr_table_entry* tableEntry,
673 const std::string& attrName,
674 const BIOSTable& BIOSStringTable, Table& table)>;
675
676using AttrType = uint8_t;
677const std::map<AttrType, AttrValTableEntryConstructHandler>
678 AttrValTableConstructMap{
679 {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry},
680 {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry},
681 {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry},
682 {PLDM_BIOS_ENUMERATION_READ_ONLY,
683 bios_type_enum::constructAttrValueEntry},
John Wangdbbc9ff2019-10-25 13:53:46 +0800684 {PLDM_BIOS_INTEGER, bios_type_integer::constructAttrValueEntry},
685 {PLDM_BIOS_INTEGER_READ_ONLY,
686 bios_type_integer::constructAttrValueEntry},
John Wang3ad21752019-10-06 16:42:21 +0800687 };
688
689void constructAttrValueTableEntry(
690 const struct pldm_bios_attr_table_entry* attrEntry,
691 const BIOSTable& BIOSStringTable, Table& attributeValueTable)
692{
693 auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable);
694 if (attrName.empty())
695 {
696 log<level::ERR>("invalid string handle",
697 entry("STRING_HANDLE=%d", attrEntry->string_handle));
698 return;
699 }
700
701 AttrValTableConstructMap.at(attrEntry->attr_type)(
702 attrEntry, attrName, BIOSStringTable, attributeValueTable);
703}
704
Sampa Misrab37be312019-07-03 02:26:41 -0500705/** @brief Construct the BIOS attribute value table
706 *
707 * @param[in] BIOSAttributeValueTable - the attribute value table
708 * @param[in] BIOSAttributeTable - the attribute table
709 * @param[in] BIOSStringTable - the string table
710 * @param[in] transferHandle - transfer handle to identify part of transfer
711 * @param[in] transferOpFlag - flag to indicate which part of data being
712 * transferred
713 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500714 */
715Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
716 const BIOSTable& BIOSAttributeTable,
717 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500718 uint32_t& /*transferHandle*/,
719 uint8_t& /*transferOpFlag*/,
John Wang3ad21752019-10-06 16:42:21 +0800720 uint8_t instanceID)
Sampa Misrab37be312019-07-03 02:26:41 -0500721{
722 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
723 0);
724 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
725 uint32_t nxtTransferHandle = 0;
726 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500727
John Wang3ad21752019-10-06 16:42:21 +0800728 if (!BIOSAttributeValueTable.isEmpty())
729 {
Sampa Misrab37be312019-07-03 02:26:41 -0500730 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
John Wang3ad21752019-10-06 16:42:21 +0800731 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500732 responsePtr); // filling up the header here
733 BIOSAttributeValueTable.load(response);
John Wang3ad21752019-10-06 16:42:21 +0800734 return response;
Sampa Misrab37be312019-07-03 02:26:41 -0500735 }
736
John Wang3ad21752019-10-06 16:42:21 +0800737 Table attributeValueTable;
738 Table attributeTable;
739 BIOSAttributeTable.load(attributeTable);
740 traverseBIOSAttrTable(
741 attributeTable,
742 [&BIOSStringTable, &attributeValueTable](
743 const struct pldm_bios_attr_table_entry* tableEntry) {
744 constructAttrValueTableEntry(tableEntry, BIOSStringTable,
745 attributeValueTable);
746 });
747 if (attributeValueTable.empty())
748 {
749 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
750 nxtTransferHandle, transferFlag, nullptr,
751 response.size(), responsePtr);
752 return response;
753 }
754 utils::padAndChecksum(attributeValueTable);
755 BIOSAttributeValueTable.store(attributeValueTable);
756
757 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
758 attributeValueTable.size());
759 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
760 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
761 transferFlag, attributeValueTable.data(),
762 response.size(), responsePtr);
763
Sampa Misrab37be312019-07-03 02:26:41 -0500764 return response;
765}
766
767Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
768{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500769 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500770 auto response = internal::buildBIOSTables(request, payloadLength,
771 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
772
773 return response;
774}
775
776namespace bios
777{
778
779void registerHandlers()
780{
781 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
782 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
783}
784
785namespace internal
786{
787
788Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
789 const char* biosJsonDir, const char* biosTablePath)
790{
791 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
792 0);
793 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
794
John Wange96e7e52019-10-05 17:47:30 +0800795 if (setupConfig(biosJsonDir) != 0)
796 {
797 encode_get_bios_table_resp(
798 request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE,
799 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr,
800 response.size(), responsePtr);
801 return response;
802 }
803
Sampa Misrab37be312019-07-03 02:26:41 -0500804 uint32_t transferHandle{};
805 uint8_t transferOpFlag{};
806 uint8_t tableType{};
807
808 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
809 &transferOpFlag, &tableType);
810 if (rc == PLDM_SUCCESS)
811 {
812 BIOSTable BIOSStringTable(
813 ((std::string(biosTablePath) + "/stringTable")).c_str());
814 BIOSTable BIOSAttributeTable(
815 ((std::string(biosTablePath) + "/attributeTable")).c_str());
816 BIOSTable BIOSAttributeValueTable(
817 ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
818 switch (tableType)
819 {
820 case PLDM_BIOS_STRING_TABLE:
821
John Wange96e7e52019-10-05 17:47:30 +0800822 response = getBIOSStringTable(BIOSStringTable, transferHandle,
823 transferOpFlag,
824 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500825 break;
826 case PLDM_BIOS_ATTR_TABLE:
827
828 if (BIOSStringTable.isEmpty())
829 {
830 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
831 }
832 else
833 {
834 response = getBIOSAttributeTable(
835 BIOSAttributeTable, BIOSStringTable, transferHandle,
836 transferOpFlag, request->hdr.instance_id, biosJsonDir);
837 }
838 break;
839 case PLDM_BIOS_ATTR_VAL_TABLE:
Carol Wangf7d1a362019-11-18 15:34:14 +0800840 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty())
Sampa Misrab37be312019-07-03 02:26:41 -0500841 {
842 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
843 }
844 else
845 {
846 response = getBIOSAttributeValueTable(
847 BIOSAttributeValueTable, BIOSAttributeTable,
848 BIOSStringTable, transferHandle, transferOpFlag,
John Wang3ad21752019-10-06 16:42:21 +0800849 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500850 }
851 break;
852 default:
853 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
854 break;
855 }
856 }
857
858 if (rc != PLDM_SUCCESS)
859 {
860 uint32_t nxtTransferHandle{};
861 uint8_t transferFlag{};
862 size_t respPayloadLength{};
863
864 encode_get_bios_table_resp(request->hdr.instance_id, rc,
865 nxtTransferHandle, transferFlag, nullptr,
866 respPayloadLength, responsePtr);
867 }
868
869 return response;
870}
871
872} // end namespace internal
873} // namespace bios
874
Sampa Misra032bd502019-03-06 05:03:22 -0600875} // namespace responder
876} // namespace pldm