blob: e9ed6280132681185074c848f96774a319834075 [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>
Deepak Kodihallid9fb1522019-11-28 10:06:34 -060010#include <filesystem>
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
Deepak Kodihallid9fb1522019-11-28 10:06:34 -060020namespace fs = std::filesystem;
Sampa Misrab37be312019-07-03 02:26:41 -050021using namespace pldm::responder::bios;
22using namespace bios_parser;
Sampa Misrab37be312019-07-03 02:26:41 -050023
Deepak Kodihallid9fb1522019-11-28 10:06:34 -060024constexpr auto stringTableFile = "stringTable";
25constexpr auto attrTableFile = "attributeTable";
26constexpr auto attrValTableFile = "attributeValueTable";
27
Sampa Misra032bd502019-03-06 05:03:22 -060028namespace pldm
29{
30
31using namespace phosphor::logging;
Sampa Misrab37be312019-07-03 02:26:41 -050032using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Sampa Misra032bd502019-03-06 05:03:22 -060033using EpochTimeUS = uint64_t;
Sampa Misrab37be312019-07-03 02:26:41 -050034using BIOSTableRow = std::vector<uint8_t>;
Carol Wangdc220c82019-08-26 13:31:31 +080035using BIOSJsonName = std::string;
Sampa Misra032bd502019-03-06 05:03:22 -060036
37constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
Sampa Misrab37be312019-07-03 02:26:41 -050038constexpr auto padChksumMax = 7;
Sampa Misra032bd502019-03-06 05:03:22 -060039
40namespace responder
41{
42
43namespace utils
44{
45
46void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
47 uint8_t& hours, uint8_t& day, uint8_t& month,
48 uint16_t& year)
49{
50 auto t = time_t(timeSec);
51 auto time = localtime(&t);
52
53 seconds = decimalToBcd(time->tm_sec);
54 minutes = decimalToBcd(time->tm_min);
55 hours = decimalToBcd(time->tm_hour);
56 day = decimalToBcd(time->tm_mday);
57 month =
58 decimalToBcd(time->tm_mon + 1); // The number of months in the range
59 // 0 to 11.PLDM expects range 1 to 12
60 year = decimalToBcd(time->tm_year + 1900); // The number of years since 1900
61}
62
John Wangc2938352019-09-30 13:58:41 +080063size_t getTableTotalsize(size_t sizeWithoutPad)
64{
John Wang79c37f12019-10-31 15:46:31 +080065 return sizeWithoutPad + pldm_bios_table_pad_checksum_size(sizeWithoutPad);
John Wangc2938352019-09-30 13:58:41 +080066}
67
68void padAndChecksum(Table& table)
69{
John Wang79c37f12019-10-31 15:46:31 +080070 auto sizeWithoutPad = table.size();
71 auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad);
72 table.resize(table.size() + padAndChecksumSize);
John Wangc2938352019-09-30 13:58:41 +080073
John Wang79c37f12019-10-31 15:46:31 +080074 pldm_bios_table_append_pad_checksum(table.data(), table.size(),
75 sizeWithoutPad);
John Wangc2938352019-09-30 13:58:41 +080076}
77
Sampa Misra032bd502019-03-06 05:03:22 -060078} // namespace utils
79
Deepak Kodihallibc669f12019-11-28 08:52:07 -060080namespace bios
81{
82
Deepak Kodihallid9fb1522019-11-28 10:06:34 -060083Handler::Handler()
84{
85 try
86 {
87 fs::remove(
88 fs::path(std::string(BIOS_TABLES_DIR) + "/" + stringTableFile));
89 fs::remove(
90 fs::path(std::string(BIOS_TABLES_DIR) + "/" + attrTableFile));
91 fs::remove(
92 fs::path(std::string(BIOS_TABLES_DIR) + "/" + attrValTableFile));
93 }
94 catch (const std::exception& e)
95 {
96 }
97
98 handlers.emplace(PLDM_GET_DATE_TIME,
99 [this](const pldm_msg* request, size_t payloadLength) {
100 return this->getDateTime(request, payloadLength);
101 });
102 handlers.emplace(PLDM_GET_BIOS_TABLE,
103 [this](const pldm_msg* request, size_t payloadLength) {
104 return this->getBIOSTable(request, payloadLength);
105 });
106}
107
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600108Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -0600109{
110 uint8_t seconds = 0;
111 uint8_t minutes = 0;
112 uint8_t hours = 0;
113 uint8_t day = 0;
114 uint8_t month = 0;
115 uint16_t year = 0;
116
117 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liu408c3c42019-10-16 16:49:15 +0800118 constexpr auto hostTimePath = "/xyz/openbmc_project/time/host";
vkaverapa6575b82019-04-03 05:33:52 -0500119 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
120 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misra032bd502019-03-06 05:03:22 -0600121 std::variant<EpochTimeUS> value;
122
123 auto bus = sdbusplus::bus::new_default();
124 try
125 {
George Liu408c3c42019-10-16 16:49:15 +0800126 auto service = getService(bus, hostTimePath, timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -0600127
George Liu408c3c42019-10-16 16:49:15 +0800128 auto method = bus.new_method_call(service.c_str(), hostTimePath,
Sampa Misra032bd502019-03-06 05:03:22 -0600129 dbusProperties, "Get");
130 method.append(timeInterface, "Elapsed");
131
132 auto reply = bus.call(method);
133 reply.read(value);
134 }
135
136 catch (std::exception& e)
137 {
George Liu408c3c42019-10-16 16:49:15 +0800138 log<level::ERR>("Error getting time", entry("PATH=%s", hostTimePath),
Sampa Misra032bd502019-03-06 05:03:22 -0600139 entry("TIME INTERACE=%s", timeInterface));
140
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530141 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
142 minutes, hours, day, month, year,
143 responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500144 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600145 }
146
147 uint64_t timeUsec = std::get<EpochTimeUS>(value);
148
149 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
150 std::chrono::microseconds(timeUsec))
151 .count();
152
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600153 pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours,
154 day, month, year);
Sampa Misra032bd502019-03-06 05:03:22 -0600155
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530156 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
157 minutes, hours, day, month, year, responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500158 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600159}
160
Sampa Misrab37be312019-07-03 02:26:41 -0500161/** @brief Construct the BIOS string table
162 *
163 * @param[in] BIOSStringTable - the string table
164 * @param[in] transferHandle - transfer handle to identify part of transfer
165 * @param[in] transferOpFlag - flag to indicate which part of data being
166 * transferred
167 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500168 */
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500169Response getBIOSStringTable(BIOSTable& BIOSStringTable,
170 uint32_t /*transferHandle*/,
John Wange96e7e52019-10-05 17:47:30 +0800171 uint8_t /*transferOpFlag*/, uint8_t instanceID)
172
Sampa Misrab37be312019-07-03 02:26:41 -0500173{
174 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
175 0);
176 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
John Wangdd9a6282019-10-11 18:52:46 +0800177 if (!BIOSStringTable.isEmpty())
178 {
179 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS,
180 0, /* next transfer handle */
181 PLDM_START_AND_END, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500182 responsePtr); // filling up the header here
183 BIOSStringTable.load(response);
John Wangdd9a6282019-10-11 18:52:46 +0800184 return response;
185 }
186 auto biosStrings = bios_parser::getStrings();
187 std::sort(biosStrings.begin(), biosStrings.end());
188 // remove all duplicate strings received from bios json
189 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
190 biosStrings.end());
191
192 size_t sizeWithoutPad = std::accumulate(
193 biosStrings.begin(), biosStrings.end(), 0,
194 [](size_t sum, const std::string& elem) {
195 return sum +
196 pldm_bios_table_string_entry_encode_length(elem.length());
197 });
198
199 Table stringTable;
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600200 stringTable.reserve(
201 pldm::responder::utils::getTableTotalsize(sizeWithoutPad));
John Wangdd9a6282019-10-11 18:52:46 +0800202
203 stringTable.resize(sizeWithoutPad);
204 auto tablePtr = stringTable.data();
205 for (const auto& elem : biosStrings)
206 {
207 auto entry_length =
208 pldm_bios_table_string_entry_encode_length(elem.length());
209 pldm_bios_table_string_entry_encode(tablePtr, sizeWithoutPad,
210 elem.c_str(), elem.length());
211 tablePtr += entry_length;
212 sizeWithoutPad -= entry_length;
Sampa Misrab37be312019-07-03 02:26:41 -0500213 }
214
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600215 pldm::responder::utils::padAndChecksum(stringTable);
John Wangdd9a6282019-10-11 18:52:46 +0800216 BIOSStringTable.store(stringTable);
217 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
218 stringTable.size(),
219 0);
220 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
221 encode_get_bios_table_resp(
222 instanceID, PLDM_SUCCESS, 0 /* nxtTransferHandle */, PLDM_START_AND_END,
223 stringTable.data(), response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500224 return response;
225}
226
227/** @brief Find the string handle from the BIOS string table given the name
228 *
229 * @param[in] name - name of the BIOS string
230 * @param[in] BIOSStringTable - the string table
231 * @return - uint16_t - handle of the string
232 */
233StringHandle findStringHandle(const std::string& name,
234 const BIOSTable& BIOSStringTable)
235{
John Wangdd9a6282019-10-11 18:52:46 +0800236 Table table;
237 BIOSStringTable.load(table);
238 auto stringEntry = pldm_bios_table_string_find_by_string(
239 table.data(), table.size(), name.c_str());
240 if (stringEntry == nullptr)
Sampa Misrab37be312019-07-03 02:26:41 -0500241 {
John Wangdd9a6282019-10-11 18:52:46 +0800242 log<level::ERR>("Reached end of BIOS string table,did not find the "
243 "handle for the string",
244 entry("STRING=%s", name.c_str()));
245 elog<InternalFailure>();
Sampa Misrab37be312019-07-03 02:26:41 -0500246 }
John Wangdd9a6282019-10-11 18:52:46 +0800247
248 return pldm_bios_table_string_entry_decode_handle(stringEntry);
Sampa Misrab37be312019-07-03 02:26:41 -0500249}
250
251/** @brief Find the string name from the BIOS string table for a string handle
252 *
253 * @param[in] stringHdl - string handle
254 * @param[in] BIOSStringTable - the string table
255 *
256 * @return - std::string - name of the corresponding BIOS string
257 */
258std::string findStringName(StringHandle stringHdl,
259 const BIOSTable& BIOSStringTable)
260{
John Wangdd9a6282019-10-11 18:52:46 +0800261 Table table;
262 BIOSStringTable.load(table);
263 auto stringEntry = pldm_bios_table_string_find_by_handle(
264 table.data(), table.size(), stringHdl);
Sampa Misrab37be312019-07-03 02:26:41 -0500265 std::string name;
John Wangdd9a6282019-10-11 18:52:46 +0800266 if (stringEntry == nullptr)
Sampa Misrab37be312019-07-03 02:26:41 -0500267 {
John Wangdd9a6282019-10-11 18:52:46 +0800268 log<level::ERR>("Reached end of BIOS string table,did not find "
269 "string name for handle",
270 entry("STRING_HANDLE=%d", stringHdl));
Sampa Misrab37be312019-07-03 02:26:41 -0500271 }
John Wangdd9a6282019-10-11 18:52:46 +0800272 auto strLength =
273 pldm_bios_table_string_entry_decode_string_length(stringEntry);
274 name.resize(strLength);
275 pldm_bios_table_string_entry_decode_string(stringEntry, name.data(),
276 name.size());
Sampa Misrab37be312019-07-03 02:26:41 -0500277 return name;
278}
279
280namespace bios_type_enum
281{
282
Carol Wangdc220c82019-08-26 13:31:31 +0800283using namespace bios_parser::bios_enum;
284
Sampa Misrab37be312019-07-03 02:26:41 -0500285/** @brief Find the indices into the array of the possible values of string
286 * handles for the current values.This is used in attribute value table
287 *
288 * @param[in] possiVals - vector of string handles comprising all the possible
289 * values for an attribute
290 * @param[in] currVals - vector of strings comprising all current values
291 * for an attribute
292 * @param[in] BIOSStringTable - the string table
293 *
294 * @return - std::vector<uint8_t> - indices into the array of the possible
295 * values of string handles
296 */
297std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
298 CurrentValues currVals,
299 const BIOSTable& BIOSStringTable)
300{
301 std::vector<uint8_t> stringIndices;
302
303 for (const auto& currVal : currVals)
304 {
305 StringHandle curHdl;
306 try
307 {
308 curHdl = findStringHandle(currVal, BIOSStringTable);
309 }
310 catch (InternalFailure& e)
311 {
312 log<level::ERR>("Exception fetching handle for the string",
313 entry("STRING=%s", currVal.c_str()));
314 continue;
315 }
316
317 uint8_t i = 0;
318 for (auto possiHdl : possiVals)
319 {
320 if (possiHdl == curHdl)
321 {
322 stringIndices.push_back(i);
323 break;
324 }
325 i++;
326 }
327 }
328 return stringIndices;
329}
330
331/** @brief Find the indices into the array of the possible values of string
332 * handles for the default values. This is used in attribute table
333 *
334 * @param[in] possiVals - vector of strings comprising all the possible values
335 * for an attribute
336 * @param[in] defVals - vector of strings comprising all the default values
337 * for an attribute
338 * @return - std::vector<uint8_t> - indices into the array of the possible
339 * values of string
340 */
341std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
342 const DefaultValues& defVals)
343{
344 std::vector<uint8_t> defHdls;
345 for (const auto& defs : defVals)
346 {
347 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
348 if (index != possiVals.end())
349 {
350 defHdls.push_back(index - possiVals.begin());
351 }
352 }
353
354 return defHdls;
355}
356
357/** @brief Construct the attibute table for BIOS type Enumeration and
358 * Enumeration ReadOnly
359 * @param[in] BIOSStringTable - the string table
360 * @param[in] biosJsonDir - path where the BIOS json files are present
Carol Wangdc220c82019-08-26 13:31:31 +0800361 * @param[in,out] attributeTable - the attribute table
Sampa Misrab37be312019-07-03 02:26:41 -0500362 *
Sampa Misrab37be312019-07-03 02:26:41 -0500363 */
John Wange96e7e52019-10-05 17:47:30 +0800364void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500365{
Sampa Misrab37be312019-07-03 02:26:41 -0500366 const auto& attributeMap = getValues();
Sampa Misrab37be312019-07-03 02:26:41 -0500367 StringHandle strHandle;
368
369 for (const auto& [key, value] : attributeMap)
370 {
371 try
372 {
373 strHandle = findStringHandle(key, BIOSStringTable);
374 }
375 catch (InternalFailure& e)
376 {
377 log<level::ERR>("Could not find handle for BIOS string",
378 entry("ATTRIBUTE=%s", key.c_str()));
379 continue;
380 }
John Wangccc04552019-10-14 14:28:25 +0800381 bool readOnly = (std::get<0>(value));
Sampa Misrab37be312019-07-03 02:26:41 -0500382 PossibleValues possiVals = std::get<1>(value);
383 DefaultValues defVals = std::get<2>(value);
384 // both the possible and default values are stored in sorted manner to
385 // ease in fetching back/comparison
386 std::sort(possiVals.begin(), possiVals.end());
387 std::sort(defVals.begin(), defVals.end());
388
389 std::vector<StringHandle> possiValsByHdl;
390 for (const auto& elem : possiVals)
391 {
392 try
393 {
394 auto hdl = findStringHandle(elem, BIOSStringTable);
395 possiValsByHdl.push_back(std::move(hdl));
396 }
397 catch (InternalFailure& e)
398 {
399 log<level::ERR>("Could not find handle for BIOS string",
400 entry("STRING=%s", elem.c_str()));
401 continue;
402 }
403 }
404 auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
John Wangccc04552019-10-14 14:28:25 +0800405 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
406 possiValsByHdl.size(), defValsByHdl.size());
Sampa Misrab37be312019-07-03 02:26:41 -0500407
John Wangccc04552019-10-14 14:28:25 +0800408 auto attrTableSize = attributeTable.size();
409 attributeTable.resize(attrTableSize + entryLength, 0);
410 struct pldm_bios_table_attr_entry_enum_info info = {
411 strHandle,
412 readOnly,
413 (uint8_t)possiValsByHdl.size(),
414 possiValsByHdl.data(),
415 (uint8_t)defValsByHdl.size(),
416 defValsByHdl.data(),
417 };
418 pldm_bios_table_attr_entry_enum_encode(
419 attributeTable.data() + attrTableSize, entryLength, &info);
Sampa Misrab37be312019-07-03 02:26:41 -0500420 }
Sampa Misrab37be312019-07-03 02:26:41 -0500421}
422
John Wang3ad21752019-10-06 16:42:21 +0800423void constructAttrValueEntry(
424 const struct pldm_bios_attr_table_entry* attrTableEntry,
425 const std::string& attrName, const BIOSTable& BIOSStringTable,
426 Table& attrValueTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500427{
John Wang3ad21752019-10-06 16:42:21 +0800428 CurrentValues currVals;
429 try
Sampa Misrab37be312019-07-03 02:26:41 -0500430 {
John Wang3ad21752019-10-06 16:42:21 +0800431 currVals = getAttrValue(attrName);
Sampa Misrab37be312019-07-03 02:26:41 -0500432 }
John Wang3ad21752019-10-06 16:42:21 +0800433 catch (const std::exception& e)
434 {
435 log<level::ERR>("getAttrValue returned error for attribute",
436 entry("NAME=%s", attrName.c_str()),
437 entry("ERROR=%s", e.what()));
438 return;
439 }
440 uint8_t pv_num =
441 pldm_bios_table_attr_entry_enum_decode_pv_num(attrTableEntry);
442 PossibleValuesByHandle pvHdls(pv_num, 0);
443 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrTableEntry,
444 pvHdls.data(), pv_num);
445 std::sort(currVals.begin(), currVals.end());
446
447 auto currValStrIndices = findStrIndices(pvHdls, currVals, BIOSStringTable);
448
449 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
450 currValStrIndices.size());
451 auto tableSize = attrValueTable.size();
452 attrValueTable.resize(tableSize + entryLength);
453 pldm_bios_table_attr_value_entry_encode_enum(
454 attrValueTable.data() + tableSize, entryLength,
455 attrTableEntry->attr_handle, attrTableEntry->attr_type,
456 currValStrIndices.size(), currValStrIndices.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500457}
458
459} // end namespace bios_type_enum
460
Carol Wangdc220c82019-08-26 13:31:31 +0800461namespace bios_type_string
462{
Carol Wang612f35b2019-08-26 17:14:26 +0800463
464using namespace bios_parser::bios_string;
465
Carol Wangdc220c82019-08-26 13:31:31 +0800466/** @brief Construct the attibute table for BIOS type String and
467 * String ReadOnly
468 * @param[in] BIOSStringTable - the string table
469 * @param[in] biosJsonDir - path where the BIOS json files are present
470 * @param[in,out] attributeTable - the attribute table
471 *
472 */
John Wange96e7e52019-10-05 17:47:30 +0800473void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800474{
Carol Wang612f35b2019-08-26 17:14:26 +0800475 const auto& attributeMap = getValues();
476 StringHandle strHandle;
Carol Wang612f35b2019-08-26 17:14:26 +0800477 for (const auto& [key, value] : attributeMap)
478 {
479 try
480 {
481 strHandle = findStringHandle(key, BIOSStringTable);
482 }
483 catch (InternalFailure& e)
484 {
485 log<level::ERR>("Could not find handle for BIOS string",
486 entry("ATTRIBUTE=%s", key.c_str()));
487 continue;
488 }
489
John Wangccc04552019-10-14 14:28:25 +0800490 const auto& [readOnly, strType, minStrLen, maxStrLen, defaultStrLen,
Carol Wang612f35b2019-08-26 17:14:26 +0800491 defaultStr] = value;
John Wangccc04552019-10-14 14:28:25 +0800492 auto entryLength =
493 pldm_bios_table_attr_entry_string_encode_length(defaultStrLen);
Carol Wang612f35b2019-08-26 17:14:26 +0800494
John Wangccc04552019-10-14 14:28:25 +0800495 struct pldm_bios_table_attr_entry_string_info info = {
496 strHandle, readOnly, strType, minStrLen,
497 maxStrLen, defaultStrLen, defaultStr.data(),
498 };
499 auto attrTableSize = attributeTable.size();
500 attributeTable.resize(attrTableSize + entryLength, 0);
501 pldm_bios_table_attr_entry_string_encode(
502 attributeTable.data() + attrTableSize, entryLength, &info);
Carol Wang612f35b2019-08-26 17:14:26 +0800503 }
Carol Wangdc220c82019-08-26 13:31:31 +0800504}
Carol Wangb503f9e2019-09-02 16:34:10 +0800505
John Wang3ad21752019-10-06 16:42:21 +0800506void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
507 const std::string& attrName,
Carol Wangb503f9e2019-09-02 16:34:10 +0800508 const BIOSTable& BIOSStringTable,
John Wang3ad21752019-10-06 16:42:21 +0800509 Table& attrValueTable)
Carol Wangb503f9e2019-09-02 16:34:10 +0800510{
John Wang3ad21752019-10-06 16:42:21 +0800511 std::ignore = BIOSStringTable;
512 std::string currStr;
513 uint16_t currStrLen = 0;
514 try
Carol Wangb503f9e2019-09-02 16:34:10 +0800515 {
John Wang3ad21752019-10-06 16:42:21 +0800516 currStr = getAttrValue(attrName);
517 currStrLen = currStr.size();
Carol Wangb503f9e2019-09-02 16:34:10 +0800518 }
John Wang3ad21752019-10-06 16:42:21 +0800519 catch (const std::exception& e)
520 {
521 log<level::ERR>("getAttrValue returned error for attribute",
522 entry("NAME=%s", attrName.c_str()),
523 entry("ERROR=%s", e.what()));
524 return;
525 }
526 auto entryLength =
527 pldm_bios_table_attr_value_entry_encode_string_length(currStrLen);
528 auto tableSize = attrValueTable.size();
529 attrValueTable.resize(tableSize + entryLength);
530 pldm_bios_table_attr_value_entry_encode_string(
531 attrValueTable.data() + tableSize, entryLength,
532 attrTableEntry->attr_handle, attrTableEntry->attr_type, currStrLen,
533 currStr.c_str());
Carol Wangb503f9e2019-09-02 16:34:10 +0800534}
535
Carol Wangdc220c82019-08-26 13:31:31 +0800536} // end namespace bios_type_string
537
John Wangdbbc9ff2019-10-25 13:53:46 +0800538namespace bios_type_integer
539{
540
541using namespace bios_parser::bios_integer;
542
543/** @brief Construct the attibute table for BIOS type Integer and
544 * Integer ReadOnly
545 * @param[in] BIOSStringTable - the string table
546 * @param[in,out] attributeTable - the attribute table
547 *
548 */
549void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
550{
551 const auto& attributeMap = getValues();
552 StringHandle strHandle;
553 for (const auto& [key, value] : attributeMap)
554 {
555 try
556 {
557 strHandle = findStringHandle(key, BIOSStringTable);
558 }
559 catch (InternalFailure& e)
560 {
561 log<level::ERR>("Could not find handle for BIOS string",
562 entry("ATTRIBUTE=%s", key.c_str()));
563 continue;
564 }
565
566 const auto& [readOnly, lowerBound, upperBound, scalarIncrement,
567 defaultValue] = value;
568 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
569
570 struct pldm_bios_table_attr_entry_integer_info info = {
571 strHandle, readOnly, lowerBound,
572 upperBound, scalarIncrement, defaultValue,
573 };
574 auto attrTableSize = attributeTable.size();
575 attributeTable.resize(attrTableSize + entryLength, 0);
576 pldm_bios_table_attr_entry_integer_encode(
577 attributeTable.data() + attrTableSize, entryLength, &info);
578 }
579}
580
581void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
582 const std::string& attrName,
583 const BIOSTable& BIOSStringTable,
584 Table& attrValueTable)
585{
586 std::ignore = BIOSStringTable;
587 uint64_t currentValue;
588 try
589 {
590 currentValue = getAttrValue(attrName);
591 }
592 catch (const std::exception& e)
593 {
594 log<level::ERR>("Failed to get attribute value",
595 entry("NAME=%s", attrName.c_str()),
596 entry("ERROR=%s", e.what()));
597 return;
598 }
599 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
600 auto tableSize = attrValueTable.size();
601 attrValueTable.resize(tableSize + entryLength);
602 pldm_bios_table_attr_value_entry_encode_integer(
603 attrValueTable.data() + tableSize, entryLength,
604 attrTableEntry->attr_handle, attrTableEntry->attr_type, currentValue);
605}
606
607} // namespace bios_type_integer
608
John Wang02700402019-10-06 16:34:29 +0800609void traverseBIOSAttrTable(const Table& biosAttrTable,
610 AttrTableEntryHandler handler)
611{
612 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
613 iter(pldm_bios_table_iter_create(biosAttrTable.data(),
614 biosAttrTable.size(),
615 PLDM_BIOS_ATTR_TABLE),
616 pldm_bios_table_iter_free);
617 while (!pldm_bios_table_iter_is_end(iter.get()))
618 {
619 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
620 try
621 {
622 handler(table_entry);
623 }
624 catch (const std::exception& e)
625 {
626 log<level::ERR>("handler fails when traversing BIOSAttrTable",
627 entry("ERROR=%s", e.what()));
628 }
629 pldm_bios_table_iter_next(iter.get());
630 }
631}
632
John Wange96e7e52019-10-05 17:47:30 +0800633using typeHandler = std::function<void(const BIOSTable& BIOSStringTable,
634 Table& attributeTable)>;
Carol Wangdc220c82019-08-26 13:31:31 +0800635std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
636 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
John Wangdbbc9ff2019-10-25 13:53:46 +0800637 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable},
638 {bios_parser::bIOSIntegerJson, bios_type_integer::constructAttrTable},
639};
Carol Wangdc220c82019-08-26 13:31:31 +0800640
Sampa Misrab37be312019-07-03 02:26:41 -0500641/** @brief Construct the BIOS attribute table
642 *
643 * @param[in] BIOSAttributeTable - the attribute table
644 * @param[in] BIOSStringTable - the string table
645 * @param[in] transferHandle - transfer handle to identify part of transfer
646 * @param[in] transferOpFlag - flag to indicate which part of data being
647 * transferred
648 * @param[in] instanceID - instance ID to identify the command
649 * @param[in] biosJsonDir - path where the BIOS json files are present
650 */
651Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
652 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500653 uint32_t /*transferHandle*/,
654 uint8_t /*transferOpFlag*/, uint8_t instanceID,
655 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500656{
657 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
658 0);
659 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
660 uint32_t nxtTransferHandle = 0;
661 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500662
663 if (BIOSAttributeTable.isEmpty())
664 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800665 Table attributeTable;
666 fs::path dir(biosJsonDir);
667
668 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
669 it++)
670 {
671 fs::path file = dir / it->first;
672 if (fs::exists(file))
673 {
John Wange96e7e52019-10-05 17:47:30 +0800674 it->second(BIOSStringTable, attributeTable);
Carol Wangdc220c82019-08-26 13:31:31 +0800675 }
676 }
677
678 if (attributeTable.empty())
679 { // no available json file is found
680 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
681 nxtTransferHandle, transferFlag, nullptr,
682 response.size(), responsePtr);
683 return response;
684 }
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600685 pldm::responder::utils::padAndChecksum(attributeTable);
John Wangc2938352019-09-30 13:58:41 +0800686 BIOSAttributeTable.store(attributeTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500687 response.resize(sizeof(pldm_msg_hdr) +
688 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
689 attributeTable.size());
690 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500691 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
692 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800693 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500694 }
695 else
696 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500697 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800698 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500699 responsePtr); // filling up the header here
700 BIOSAttributeTable.load(response);
701 }
702
703 return response;
704}
705
John Wang3ad21752019-10-06 16:42:21 +0800706using AttrValTableEntryConstructHandler =
707 std::function<void(const struct pldm_bios_attr_table_entry* tableEntry,
708 const std::string& attrName,
709 const BIOSTable& BIOSStringTable, Table& table)>;
710
711using AttrType = uint8_t;
712const std::map<AttrType, AttrValTableEntryConstructHandler>
713 AttrValTableConstructMap{
714 {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry},
715 {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry},
716 {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry},
717 {PLDM_BIOS_ENUMERATION_READ_ONLY,
718 bios_type_enum::constructAttrValueEntry},
John Wangdbbc9ff2019-10-25 13:53:46 +0800719 {PLDM_BIOS_INTEGER, bios_type_integer::constructAttrValueEntry},
720 {PLDM_BIOS_INTEGER_READ_ONLY,
721 bios_type_integer::constructAttrValueEntry},
John Wang3ad21752019-10-06 16:42:21 +0800722 };
723
724void constructAttrValueTableEntry(
725 const struct pldm_bios_attr_table_entry* attrEntry,
726 const BIOSTable& BIOSStringTable, Table& attributeValueTable)
727{
728 auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable);
729 if (attrName.empty())
730 {
731 log<level::ERR>("invalid string handle",
732 entry("STRING_HANDLE=%d", attrEntry->string_handle));
733 return;
734 }
735
736 AttrValTableConstructMap.at(attrEntry->attr_type)(
737 attrEntry, attrName, BIOSStringTable, attributeValueTable);
738}
739
Sampa Misrab37be312019-07-03 02:26:41 -0500740/** @brief Construct the BIOS attribute value table
741 *
742 * @param[in] BIOSAttributeValueTable - the attribute value table
743 * @param[in] BIOSAttributeTable - the attribute table
744 * @param[in] BIOSStringTable - the string table
745 * @param[in] transferHandle - transfer handle to identify part of transfer
746 * @param[in] transferOpFlag - flag to indicate which part of data being
747 * transferred
748 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500749 */
750Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
751 const BIOSTable& BIOSAttributeTable,
752 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500753 uint32_t& /*transferHandle*/,
754 uint8_t& /*transferOpFlag*/,
John Wang3ad21752019-10-06 16:42:21 +0800755 uint8_t instanceID)
Sampa Misrab37be312019-07-03 02:26:41 -0500756{
757 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
758 0);
759 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
760 uint32_t nxtTransferHandle = 0;
761 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500762
John Wang3ad21752019-10-06 16:42:21 +0800763 if (!BIOSAttributeValueTable.isEmpty())
764 {
Sampa Misrab37be312019-07-03 02:26:41 -0500765 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
John Wang3ad21752019-10-06 16:42:21 +0800766 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500767 responsePtr); // filling up the header here
768 BIOSAttributeValueTable.load(response);
John Wang3ad21752019-10-06 16:42:21 +0800769 return response;
Sampa Misrab37be312019-07-03 02:26:41 -0500770 }
771
John Wang3ad21752019-10-06 16:42:21 +0800772 Table attributeValueTable;
773 Table attributeTable;
774 BIOSAttributeTable.load(attributeTable);
775 traverseBIOSAttrTable(
776 attributeTable,
777 [&BIOSStringTable, &attributeValueTable](
778 const struct pldm_bios_attr_table_entry* tableEntry) {
779 constructAttrValueTableEntry(tableEntry, BIOSStringTable,
780 attributeValueTable);
781 });
782 if (attributeValueTable.empty())
783 {
784 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
785 nxtTransferHandle, transferFlag, nullptr,
786 response.size(), responsePtr);
787 return response;
788 }
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600789 pldm::responder::utils::padAndChecksum(attributeValueTable);
John Wang3ad21752019-10-06 16:42:21 +0800790 BIOSAttributeValueTable.store(attributeValueTable);
791
792 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
793 attributeValueTable.size());
794 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
795 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
796 transferFlag, attributeValueTable.data(),
797 response.size(), responsePtr);
798
Sampa Misrab37be312019-07-03 02:26:41 -0500799 return response;
800}
801
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600802Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength)
Sampa Misrab37be312019-07-03 02:26:41 -0500803{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500804 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500805 auto response = internal::buildBIOSTables(request, payloadLength,
806 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
807
808 return response;
809}
810
Sampa Misrab37be312019-07-03 02:26:41 -0500811namespace internal
812{
813
814Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
815 const char* biosJsonDir, const char* biosTablePath)
816{
817 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
818 0);
819 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
820
John Wange96e7e52019-10-05 17:47:30 +0800821 if (setupConfig(biosJsonDir) != 0)
822 {
823 encode_get_bios_table_resp(
824 request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE,
825 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr,
826 response.size(), responsePtr);
827 return response;
828 }
829
Sampa Misrab37be312019-07-03 02:26:41 -0500830 uint32_t transferHandle{};
831 uint8_t transferOpFlag{};
832 uint8_t tableType{};
833
834 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
835 &transferOpFlag, &tableType);
836 if (rc == PLDM_SUCCESS)
837 {
838 BIOSTable BIOSStringTable(
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600839 (std::string(biosTablePath) + "/" + stringTableFile).c_str());
Sampa Misrab37be312019-07-03 02:26:41 -0500840 BIOSTable BIOSAttributeTable(
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600841 (std::string(biosTablePath) + "/" + attrTableFile).c_str());
Sampa Misrab37be312019-07-03 02:26:41 -0500842 BIOSTable BIOSAttributeValueTable(
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600843 (std::string(biosTablePath) + "/" + attrValTableFile).c_str());
Sampa Misrab37be312019-07-03 02:26:41 -0500844 switch (tableType)
845 {
846 case PLDM_BIOS_STRING_TABLE:
847
John Wange96e7e52019-10-05 17:47:30 +0800848 response = getBIOSStringTable(BIOSStringTable, transferHandle,
849 transferOpFlag,
850 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500851 break;
852 case PLDM_BIOS_ATTR_TABLE:
853
854 if (BIOSStringTable.isEmpty())
855 {
856 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
857 }
858 else
859 {
860 response = getBIOSAttributeTable(
861 BIOSAttributeTable, BIOSStringTable, transferHandle,
862 transferOpFlag, request->hdr.instance_id, biosJsonDir);
863 }
864 break;
865 case PLDM_BIOS_ATTR_VAL_TABLE:
Carol Wangf7d1a362019-11-18 15:34:14 +0800866 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty())
Sampa Misrab37be312019-07-03 02:26:41 -0500867 {
868 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
869 }
870 else
871 {
872 response = getBIOSAttributeValueTable(
873 BIOSAttributeValueTable, BIOSAttributeTable,
874 BIOSStringTable, transferHandle, transferOpFlag,
John Wang3ad21752019-10-06 16:42:21 +0800875 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500876 }
877 break;
878 default:
879 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
880 break;
881 }
882 }
883
884 if (rc != PLDM_SUCCESS)
885 {
886 uint32_t nxtTransferHandle{};
887 uint8_t transferFlag{};
888 size_t respPayloadLength{};
889
890 encode_get_bios_table_resp(request->hdr.instance_id, rc,
891 nxtTransferHandle, transferFlag, nullptr,
892 respPayloadLength, responsePtr);
893 }
894
895 return response;
896}
897
898} // end namespace internal
899} // namespace bios
900
Sampa Misra032bd502019-03-06 05:03:22 -0600901} // namespace responder
902} // namespace pldm