blob: b52b674ef1d402c06c1ef45650c585a4392162e0 [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 });
John Wang8721ed62019-12-05 14:44:43 +0800106 handlers.emplace(PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE,
107 [this](const pldm_msg* request, size_t payloadLength) {
108 return this->getBIOSAttributeCurrentValueByHandle(
109 request, payloadLength);
110 });
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600111}
112
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600113Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
Sampa Misra032bd502019-03-06 05:03:22 -0600114{
115 uint8_t seconds = 0;
116 uint8_t minutes = 0;
117 uint8_t hours = 0;
118 uint8_t day = 0;
119 uint8_t month = 0;
120 uint16_t year = 0;
121
122 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
George Liu408c3c42019-10-16 16:49:15 +0800123 constexpr auto hostTimePath = "/xyz/openbmc_project/time/host";
vkaverapa6575b82019-04-03 05:33:52 -0500124 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0);
125 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misra032bd502019-03-06 05:03:22 -0600126 std::variant<EpochTimeUS> value;
127
128 auto bus = sdbusplus::bus::new_default();
129 try
130 {
George Liu408c3c42019-10-16 16:49:15 +0800131 auto service = getService(bus, hostTimePath, timeInterface);
Sampa Misra032bd502019-03-06 05:03:22 -0600132
George Liu408c3c42019-10-16 16:49:15 +0800133 auto method = bus.new_method_call(service.c_str(), hostTimePath,
Sampa Misra032bd502019-03-06 05:03:22 -0600134 dbusProperties, "Get");
135 method.append(timeInterface, "Elapsed");
136
137 auto reply = bus.call(method);
138 reply.read(value);
139 }
140
141 catch (std::exception& e)
142 {
George Liu408c3c42019-10-16 16:49:15 +0800143 log<level::ERR>("Error getting time", entry("PATH=%s", hostTimePath),
Sampa Misra032bd502019-03-06 05:03:22 -0600144 entry("TIME INTERACE=%s", timeInterface));
145
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530146 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds,
147 minutes, hours, day, month, year,
148 responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500149 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600150 }
151
152 uint64_t timeUsec = std::get<EpochTimeUS>(value);
153
154 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
155 std::chrono::microseconds(timeUsec))
156 .count();
157
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600158 pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours,
159 day, month, year);
Sampa Misra032bd502019-03-06 05:03:22 -0600160
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530161 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
162 minutes, hours, day, month, year, responsePtr);
vkaverapa6575b82019-04-03 05:33:52 -0500163 return response;
Sampa Misra032bd502019-03-06 05:03:22 -0600164}
165
Sampa Misrab37be312019-07-03 02:26:41 -0500166/** @brief Construct the BIOS string table
167 *
168 * @param[in] BIOSStringTable - the string table
169 * @param[in] transferHandle - transfer handle to identify part of transfer
170 * @param[in] transferOpFlag - flag to indicate which part of data being
171 * transferred
172 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500173 */
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500174Response getBIOSStringTable(BIOSTable& BIOSStringTable,
175 uint32_t /*transferHandle*/,
John Wange96e7e52019-10-05 17:47:30 +0800176 uint8_t /*transferOpFlag*/, uint8_t instanceID)
177
Sampa Misrab37be312019-07-03 02:26:41 -0500178{
179 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
180 0);
181 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
John Wangdd9a6282019-10-11 18:52:46 +0800182 if (!BIOSStringTable.isEmpty())
183 {
184 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS,
185 0, /* next transfer handle */
186 PLDM_START_AND_END, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500187 responsePtr); // filling up the header here
188 BIOSStringTable.load(response);
John Wangdd9a6282019-10-11 18:52:46 +0800189 return response;
190 }
191 auto biosStrings = bios_parser::getStrings();
192 std::sort(biosStrings.begin(), biosStrings.end());
193 // remove all duplicate strings received from bios json
194 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
195 biosStrings.end());
196
197 size_t sizeWithoutPad = std::accumulate(
198 biosStrings.begin(), biosStrings.end(), 0,
199 [](size_t sum, const std::string& elem) {
200 return sum +
201 pldm_bios_table_string_entry_encode_length(elem.length());
202 });
203
204 Table stringTable;
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600205 stringTable.reserve(
206 pldm::responder::utils::getTableTotalsize(sizeWithoutPad));
John Wangdd9a6282019-10-11 18:52:46 +0800207
208 stringTable.resize(sizeWithoutPad);
209 auto tablePtr = stringTable.data();
210 for (const auto& elem : biosStrings)
211 {
212 auto entry_length =
213 pldm_bios_table_string_entry_encode_length(elem.length());
214 pldm_bios_table_string_entry_encode(tablePtr, sizeWithoutPad,
215 elem.c_str(), elem.length());
216 tablePtr += entry_length;
217 sizeWithoutPad -= entry_length;
Sampa Misrab37be312019-07-03 02:26:41 -0500218 }
219
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600220 pldm::responder::utils::padAndChecksum(stringTable);
John Wangdd9a6282019-10-11 18:52:46 +0800221 BIOSStringTable.store(stringTable);
222 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
223 stringTable.size(),
224 0);
225 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
226 encode_get_bios_table_resp(
227 instanceID, PLDM_SUCCESS, 0 /* nxtTransferHandle */, PLDM_START_AND_END,
228 stringTable.data(), response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500229 return response;
230}
231
232/** @brief Find the string handle from the BIOS string table given the name
233 *
234 * @param[in] name - name of the BIOS string
235 * @param[in] BIOSStringTable - the string table
236 * @return - uint16_t - handle of the string
237 */
238StringHandle findStringHandle(const std::string& name,
239 const BIOSTable& BIOSStringTable)
240{
John Wangdd9a6282019-10-11 18:52:46 +0800241 Table table;
242 BIOSStringTable.load(table);
243 auto stringEntry = pldm_bios_table_string_find_by_string(
244 table.data(), table.size(), name.c_str());
245 if (stringEntry == nullptr)
Sampa Misrab37be312019-07-03 02:26:41 -0500246 {
John Wangdd9a6282019-10-11 18:52:46 +0800247 log<level::ERR>("Reached end of BIOS string table,did not find the "
248 "handle for the string",
249 entry("STRING=%s", name.c_str()));
250 elog<InternalFailure>();
Sampa Misrab37be312019-07-03 02:26:41 -0500251 }
John Wangdd9a6282019-10-11 18:52:46 +0800252
253 return pldm_bios_table_string_entry_decode_handle(stringEntry);
Sampa Misrab37be312019-07-03 02:26:41 -0500254}
255
256/** @brief Find the string name from the BIOS string table for a string handle
257 *
258 * @param[in] stringHdl - string handle
259 * @param[in] BIOSStringTable - the string table
260 *
261 * @return - std::string - name of the corresponding BIOS string
262 */
263std::string findStringName(StringHandle stringHdl,
264 const BIOSTable& BIOSStringTable)
265{
John Wangdd9a6282019-10-11 18:52:46 +0800266 Table table;
267 BIOSStringTable.load(table);
268 auto stringEntry = pldm_bios_table_string_find_by_handle(
269 table.data(), table.size(), stringHdl);
Sampa Misrab37be312019-07-03 02:26:41 -0500270 std::string name;
John Wangdd9a6282019-10-11 18:52:46 +0800271 if (stringEntry == nullptr)
Sampa Misrab37be312019-07-03 02:26:41 -0500272 {
John Wangdd9a6282019-10-11 18:52:46 +0800273 log<level::ERR>("Reached end of BIOS string table,did not find "
274 "string name for handle",
275 entry("STRING_HANDLE=%d", stringHdl));
Sampa Misrab37be312019-07-03 02:26:41 -0500276 }
John Wangdd9a6282019-10-11 18:52:46 +0800277 auto strLength =
278 pldm_bios_table_string_entry_decode_string_length(stringEntry);
279 name.resize(strLength);
280 pldm_bios_table_string_entry_decode_string(stringEntry, name.data(),
281 name.size());
Sampa Misrab37be312019-07-03 02:26:41 -0500282 return name;
283}
284
285namespace bios_type_enum
286{
287
Carol Wangdc220c82019-08-26 13:31:31 +0800288using namespace bios_parser::bios_enum;
289
Sampa Misrab37be312019-07-03 02:26:41 -0500290/** @brief Find the indices into the array of the possible values of string
291 * handles for the current values.This is used in attribute value table
292 *
293 * @param[in] possiVals - vector of string handles comprising all the possible
294 * values for an attribute
295 * @param[in] currVals - vector of strings comprising all current values
296 * for an attribute
297 * @param[in] BIOSStringTable - the string table
298 *
299 * @return - std::vector<uint8_t> - indices into the array of the possible
300 * values of string handles
301 */
302std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
303 CurrentValues currVals,
304 const BIOSTable& BIOSStringTable)
305{
306 std::vector<uint8_t> stringIndices;
307
308 for (const auto& currVal : currVals)
309 {
310 StringHandle curHdl;
311 try
312 {
313 curHdl = findStringHandle(currVal, BIOSStringTable);
314 }
315 catch (InternalFailure& e)
316 {
317 log<level::ERR>("Exception fetching handle for the string",
318 entry("STRING=%s", currVal.c_str()));
319 continue;
320 }
321
322 uint8_t i = 0;
323 for (auto possiHdl : possiVals)
324 {
325 if (possiHdl == curHdl)
326 {
327 stringIndices.push_back(i);
328 break;
329 }
330 i++;
331 }
332 }
333 return stringIndices;
334}
335
336/** @brief Find the indices into the array of the possible values of string
337 * handles for the default values. This is used in attribute table
338 *
339 * @param[in] possiVals - vector of strings comprising all the possible values
340 * for an attribute
341 * @param[in] defVals - vector of strings comprising all the default values
342 * for an attribute
343 * @return - std::vector<uint8_t> - indices into the array of the possible
344 * values of string
345 */
346std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
347 const DefaultValues& defVals)
348{
349 std::vector<uint8_t> defHdls;
350 for (const auto& defs : defVals)
351 {
352 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
353 if (index != possiVals.end())
354 {
355 defHdls.push_back(index - possiVals.begin());
356 }
357 }
358
359 return defHdls;
360}
361
362/** @brief Construct the attibute table for BIOS type Enumeration and
363 * Enumeration ReadOnly
364 * @param[in] BIOSStringTable - the string table
365 * @param[in] biosJsonDir - path where the BIOS json files are present
Carol Wangdc220c82019-08-26 13:31:31 +0800366 * @param[in,out] attributeTable - the attribute table
Sampa Misrab37be312019-07-03 02:26:41 -0500367 *
Sampa Misrab37be312019-07-03 02:26:41 -0500368 */
John Wange96e7e52019-10-05 17:47:30 +0800369void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500370{
Sampa Misrab37be312019-07-03 02:26:41 -0500371 const auto& attributeMap = getValues();
Sampa Misrab37be312019-07-03 02:26:41 -0500372 StringHandle strHandle;
373
374 for (const auto& [key, value] : attributeMap)
375 {
376 try
377 {
378 strHandle = findStringHandle(key, BIOSStringTable);
379 }
380 catch (InternalFailure& e)
381 {
382 log<level::ERR>("Could not find handle for BIOS string",
383 entry("ATTRIBUTE=%s", key.c_str()));
384 continue;
385 }
John Wangccc04552019-10-14 14:28:25 +0800386 bool readOnly = (std::get<0>(value));
Sampa Misrab37be312019-07-03 02:26:41 -0500387 PossibleValues possiVals = std::get<1>(value);
388 DefaultValues defVals = std::get<2>(value);
389 // both the possible and default values are stored in sorted manner to
390 // ease in fetching back/comparison
391 std::sort(possiVals.begin(), possiVals.end());
392 std::sort(defVals.begin(), defVals.end());
393
394 std::vector<StringHandle> possiValsByHdl;
395 for (const auto& elem : possiVals)
396 {
397 try
398 {
399 auto hdl = findStringHandle(elem, BIOSStringTable);
400 possiValsByHdl.push_back(std::move(hdl));
401 }
402 catch (InternalFailure& e)
403 {
404 log<level::ERR>("Could not find handle for BIOS string",
405 entry("STRING=%s", elem.c_str()));
406 continue;
407 }
408 }
409 auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
John Wangccc04552019-10-14 14:28:25 +0800410 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
411 possiValsByHdl.size(), defValsByHdl.size());
Sampa Misrab37be312019-07-03 02:26:41 -0500412
John Wangccc04552019-10-14 14:28:25 +0800413 auto attrTableSize = attributeTable.size();
414 attributeTable.resize(attrTableSize + entryLength, 0);
415 struct pldm_bios_table_attr_entry_enum_info info = {
416 strHandle,
417 readOnly,
418 (uint8_t)possiValsByHdl.size(),
419 possiValsByHdl.data(),
420 (uint8_t)defValsByHdl.size(),
421 defValsByHdl.data(),
422 };
423 pldm_bios_table_attr_entry_enum_encode(
424 attributeTable.data() + attrTableSize, entryLength, &info);
Sampa Misrab37be312019-07-03 02:26:41 -0500425 }
Sampa Misrab37be312019-07-03 02:26:41 -0500426}
427
John Wang3ad21752019-10-06 16:42:21 +0800428void constructAttrValueEntry(
429 const struct pldm_bios_attr_table_entry* attrTableEntry,
430 const std::string& attrName, const BIOSTable& BIOSStringTable,
431 Table& attrValueTable)
Sampa Misrab37be312019-07-03 02:26:41 -0500432{
John Wang3ad21752019-10-06 16:42:21 +0800433 CurrentValues currVals;
434 try
Sampa Misrab37be312019-07-03 02:26:41 -0500435 {
John Wang3ad21752019-10-06 16:42:21 +0800436 currVals = getAttrValue(attrName);
Sampa Misrab37be312019-07-03 02:26:41 -0500437 }
John Wang3ad21752019-10-06 16:42:21 +0800438 catch (const std::exception& e)
439 {
440 log<level::ERR>("getAttrValue returned error for attribute",
441 entry("NAME=%s", attrName.c_str()),
442 entry("ERROR=%s", e.what()));
443 return;
444 }
445 uint8_t pv_num =
446 pldm_bios_table_attr_entry_enum_decode_pv_num(attrTableEntry);
447 PossibleValuesByHandle pvHdls(pv_num, 0);
448 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrTableEntry,
449 pvHdls.data(), pv_num);
450 std::sort(currVals.begin(), currVals.end());
451
452 auto currValStrIndices = findStrIndices(pvHdls, currVals, BIOSStringTable);
453
454 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
455 currValStrIndices.size());
456 auto tableSize = attrValueTable.size();
457 attrValueTable.resize(tableSize + entryLength);
458 pldm_bios_table_attr_value_entry_encode_enum(
459 attrValueTable.data() + tableSize, entryLength,
460 attrTableEntry->attr_handle, attrTableEntry->attr_type,
461 currValStrIndices.size(), currValStrIndices.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500462}
463
464} // end namespace bios_type_enum
465
Carol Wangdc220c82019-08-26 13:31:31 +0800466namespace bios_type_string
467{
Carol Wang612f35b2019-08-26 17:14:26 +0800468
469using namespace bios_parser::bios_string;
470
Carol Wangdc220c82019-08-26 13:31:31 +0800471/** @brief Construct the attibute table for BIOS type String and
472 * String ReadOnly
473 * @param[in] BIOSStringTable - the string table
474 * @param[in] biosJsonDir - path where the BIOS json files are present
475 * @param[in,out] attributeTable - the attribute table
476 *
477 */
John Wange96e7e52019-10-05 17:47:30 +0800478void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
Carol Wangdc220c82019-08-26 13:31:31 +0800479{
Carol Wang612f35b2019-08-26 17:14:26 +0800480 const auto& attributeMap = getValues();
481 StringHandle strHandle;
Carol Wang612f35b2019-08-26 17:14:26 +0800482 for (const auto& [key, value] : attributeMap)
483 {
484 try
485 {
486 strHandle = findStringHandle(key, BIOSStringTable);
487 }
488 catch (InternalFailure& e)
489 {
490 log<level::ERR>("Could not find handle for BIOS string",
491 entry("ATTRIBUTE=%s", key.c_str()));
492 continue;
493 }
494
John Wangccc04552019-10-14 14:28:25 +0800495 const auto& [readOnly, strType, minStrLen, maxStrLen, defaultStrLen,
Carol Wang612f35b2019-08-26 17:14:26 +0800496 defaultStr] = value;
John Wangccc04552019-10-14 14:28:25 +0800497 auto entryLength =
498 pldm_bios_table_attr_entry_string_encode_length(defaultStrLen);
Carol Wang612f35b2019-08-26 17:14:26 +0800499
John Wangccc04552019-10-14 14:28:25 +0800500 struct pldm_bios_table_attr_entry_string_info info = {
501 strHandle, readOnly, strType, minStrLen,
502 maxStrLen, defaultStrLen, defaultStr.data(),
503 };
504 auto attrTableSize = attributeTable.size();
505 attributeTable.resize(attrTableSize + entryLength, 0);
506 pldm_bios_table_attr_entry_string_encode(
507 attributeTable.data() + attrTableSize, entryLength, &info);
Carol Wang612f35b2019-08-26 17:14:26 +0800508 }
Carol Wangdc220c82019-08-26 13:31:31 +0800509}
Carol Wangb503f9e2019-09-02 16:34:10 +0800510
John Wang3ad21752019-10-06 16:42:21 +0800511void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
512 const std::string& attrName,
Carol Wangb503f9e2019-09-02 16:34:10 +0800513 const BIOSTable& BIOSStringTable,
John Wang3ad21752019-10-06 16:42:21 +0800514 Table& attrValueTable)
Carol Wangb503f9e2019-09-02 16:34:10 +0800515{
John Wang3ad21752019-10-06 16:42:21 +0800516 std::ignore = BIOSStringTable;
517 std::string currStr;
518 uint16_t currStrLen = 0;
519 try
Carol Wangb503f9e2019-09-02 16:34:10 +0800520 {
John Wang3ad21752019-10-06 16:42:21 +0800521 currStr = getAttrValue(attrName);
522 currStrLen = currStr.size();
Carol Wangb503f9e2019-09-02 16:34:10 +0800523 }
John Wang3ad21752019-10-06 16:42:21 +0800524 catch (const std::exception& e)
525 {
526 log<level::ERR>("getAttrValue returned error for attribute",
527 entry("NAME=%s", attrName.c_str()),
528 entry("ERROR=%s", e.what()));
529 return;
530 }
531 auto entryLength =
532 pldm_bios_table_attr_value_entry_encode_string_length(currStrLen);
533 auto tableSize = attrValueTable.size();
534 attrValueTable.resize(tableSize + entryLength);
535 pldm_bios_table_attr_value_entry_encode_string(
536 attrValueTable.data() + tableSize, entryLength,
537 attrTableEntry->attr_handle, attrTableEntry->attr_type, currStrLen,
538 currStr.c_str());
Carol Wangb503f9e2019-09-02 16:34:10 +0800539}
540
Carol Wangdc220c82019-08-26 13:31:31 +0800541} // end namespace bios_type_string
542
John Wangdbbc9ff2019-10-25 13:53:46 +0800543namespace bios_type_integer
544{
545
546using namespace bios_parser::bios_integer;
547
548/** @brief Construct the attibute table for BIOS type Integer and
549 * Integer ReadOnly
550 * @param[in] BIOSStringTable - the string table
551 * @param[in,out] attributeTable - the attribute table
552 *
553 */
554void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
555{
556 const auto& attributeMap = getValues();
557 StringHandle strHandle;
558 for (const auto& [key, value] : attributeMap)
559 {
560 try
561 {
562 strHandle = findStringHandle(key, BIOSStringTable);
563 }
564 catch (InternalFailure& e)
565 {
566 log<level::ERR>("Could not find handle for BIOS string",
567 entry("ATTRIBUTE=%s", key.c_str()));
568 continue;
569 }
570
571 const auto& [readOnly, lowerBound, upperBound, scalarIncrement,
572 defaultValue] = value;
573 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
574
575 struct pldm_bios_table_attr_entry_integer_info info = {
576 strHandle, readOnly, lowerBound,
577 upperBound, scalarIncrement, defaultValue,
578 };
579 auto attrTableSize = attributeTable.size();
580 attributeTable.resize(attrTableSize + entryLength, 0);
581 pldm_bios_table_attr_entry_integer_encode(
582 attributeTable.data() + attrTableSize, entryLength, &info);
583 }
584}
585
586void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry,
587 const std::string& attrName,
588 const BIOSTable& BIOSStringTable,
589 Table& attrValueTable)
590{
591 std::ignore = BIOSStringTable;
592 uint64_t currentValue;
593 try
594 {
595 currentValue = getAttrValue(attrName);
596 }
597 catch (const std::exception& e)
598 {
599 log<level::ERR>("Failed to get attribute value",
600 entry("NAME=%s", attrName.c_str()),
601 entry("ERROR=%s", e.what()));
602 return;
603 }
604 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
605 auto tableSize = attrValueTable.size();
606 attrValueTable.resize(tableSize + entryLength);
607 pldm_bios_table_attr_value_entry_encode_integer(
608 attrValueTable.data() + tableSize, entryLength,
609 attrTableEntry->attr_handle, attrTableEntry->attr_type, currentValue);
610}
611
612} // namespace bios_type_integer
613
John Wang02700402019-10-06 16:34:29 +0800614void traverseBIOSAttrTable(const Table& biosAttrTable,
615 AttrTableEntryHandler handler)
616{
617 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
618 iter(pldm_bios_table_iter_create(biosAttrTable.data(),
619 biosAttrTable.size(),
620 PLDM_BIOS_ATTR_TABLE),
621 pldm_bios_table_iter_free);
622 while (!pldm_bios_table_iter_is_end(iter.get()))
623 {
624 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
625 try
626 {
627 handler(table_entry);
628 }
629 catch (const std::exception& e)
630 {
631 log<level::ERR>("handler fails when traversing BIOSAttrTable",
632 entry("ERROR=%s", e.what()));
633 }
634 pldm_bios_table_iter_next(iter.get());
635 }
636}
637
John Wange96e7e52019-10-05 17:47:30 +0800638using typeHandler = std::function<void(const BIOSTable& BIOSStringTable,
639 Table& attributeTable)>;
Carol Wangdc220c82019-08-26 13:31:31 +0800640std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
641 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
John Wangdbbc9ff2019-10-25 13:53:46 +0800642 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable},
643 {bios_parser::bIOSIntegerJson, bios_type_integer::constructAttrTable},
644};
Carol Wangdc220c82019-08-26 13:31:31 +0800645
Sampa Misrab37be312019-07-03 02:26:41 -0500646/** @brief Construct the BIOS attribute table
647 *
648 * @param[in] BIOSAttributeTable - the attribute table
649 * @param[in] BIOSStringTable - the string table
650 * @param[in] transferHandle - transfer handle to identify part of transfer
651 * @param[in] transferOpFlag - flag to indicate which part of data being
652 * transferred
653 * @param[in] instanceID - instance ID to identify the command
654 * @param[in] biosJsonDir - path where the BIOS json files are present
655 */
656Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
657 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500658 uint32_t /*transferHandle*/,
659 uint8_t /*transferOpFlag*/, uint8_t instanceID,
660 const char* biosJsonDir)
Sampa Misrab37be312019-07-03 02:26:41 -0500661{
662 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
663 0);
664 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
665 uint32_t nxtTransferHandle = 0;
666 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500667
668 if (BIOSAttributeTable.isEmpty())
669 { // no persisted table, constructing fresh table and response
Carol Wangdc220c82019-08-26 13:31:31 +0800670 Table attributeTable;
671 fs::path dir(biosJsonDir);
672
673 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end();
674 it++)
675 {
676 fs::path file = dir / it->first;
677 if (fs::exists(file))
678 {
John Wange96e7e52019-10-05 17:47:30 +0800679 it->second(BIOSStringTable, attributeTable);
Carol Wangdc220c82019-08-26 13:31:31 +0800680 }
681 }
682
683 if (attributeTable.empty())
684 { // no available json file is found
685 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
686 nxtTransferHandle, transferFlag, nullptr,
687 response.size(), responsePtr);
688 return response;
689 }
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600690 pldm::responder::utils::padAndChecksum(attributeTable);
John Wangc2938352019-09-30 13:58:41 +0800691 BIOSAttributeTable.store(attributeTable);
Sampa Misrab37be312019-07-03 02:26:41 -0500692 response.resize(sizeof(pldm_msg_hdr) +
693 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
694 attributeTable.size());
695 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
Sampa Misrab37be312019-07-03 02:26:41 -0500696 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
697 transferFlag, attributeTable.data(),
Carol Wangdc220c82019-08-26 13:31:31 +0800698 response.size(), responsePtr);
Sampa Misrab37be312019-07-03 02:26:41 -0500699 }
700 else
701 { // persisted table present, constructing response
Sampa Misrab37be312019-07-03 02:26:41 -0500702 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
Carol Wangdc220c82019-08-26 13:31:31 +0800703 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500704 responsePtr); // filling up the header here
705 BIOSAttributeTable.load(response);
706 }
707
708 return response;
709}
710
John Wang3ad21752019-10-06 16:42:21 +0800711using AttrValTableEntryConstructHandler =
712 std::function<void(const struct pldm_bios_attr_table_entry* tableEntry,
713 const std::string& attrName,
714 const BIOSTable& BIOSStringTable, Table& table)>;
715
716using AttrType = uint8_t;
717const std::map<AttrType, AttrValTableEntryConstructHandler>
718 AttrValTableConstructMap{
719 {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry},
720 {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry},
721 {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry},
722 {PLDM_BIOS_ENUMERATION_READ_ONLY,
723 bios_type_enum::constructAttrValueEntry},
John Wangdbbc9ff2019-10-25 13:53:46 +0800724 {PLDM_BIOS_INTEGER, bios_type_integer::constructAttrValueEntry},
725 {PLDM_BIOS_INTEGER_READ_ONLY,
726 bios_type_integer::constructAttrValueEntry},
John Wang3ad21752019-10-06 16:42:21 +0800727 };
728
729void constructAttrValueTableEntry(
730 const struct pldm_bios_attr_table_entry* attrEntry,
731 const BIOSTable& BIOSStringTable, Table& attributeValueTable)
732{
733 auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable);
734 if (attrName.empty())
735 {
736 log<level::ERR>("invalid string handle",
737 entry("STRING_HANDLE=%d", attrEntry->string_handle));
738 return;
739 }
740
741 AttrValTableConstructMap.at(attrEntry->attr_type)(
742 attrEntry, attrName, BIOSStringTable, attributeValueTable);
743}
744
Sampa Misrab37be312019-07-03 02:26:41 -0500745/** @brief Construct the BIOS attribute value table
746 *
747 * @param[in] BIOSAttributeValueTable - the attribute value table
748 * @param[in] BIOSAttributeTable - the attribute table
749 * @param[in] BIOSStringTable - the string table
750 * @param[in] transferHandle - transfer handle to identify part of transfer
751 * @param[in] transferOpFlag - flag to indicate which part of data being
752 * transferred
753 * @param[in] instanceID - instance ID to identify the command
Sampa Misrab37be312019-07-03 02:26:41 -0500754 */
755Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
756 const BIOSTable& BIOSAttributeTable,
757 const BIOSTable& BIOSStringTable,
Deepak Kodihalli3c275e12019-09-21 06:39:39 -0500758 uint32_t& /*transferHandle*/,
759 uint8_t& /*transferOpFlag*/,
John Wang3ad21752019-10-06 16:42:21 +0800760 uint8_t instanceID)
Sampa Misrab37be312019-07-03 02:26:41 -0500761{
762 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
763 0);
764 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
765 uint32_t nxtTransferHandle = 0;
766 uint8_t transferFlag = PLDM_START_AND_END;
Sampa Misrab37be312019-07-03 02:26:41 -0500767
John Wang3ad21752019-10-06 16:42:21 +0800768 if (!BIOSAttributeValueTable.isEmpty())
769 {
Sampa Misrab37be312019-07-03 02:26:41 -0500770 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
John Wang3ad21752019-10-06 16:42:21 +0800771 transferFlag, nullptr, response.size(),
Sampa Misrab37be312019-07-03 02:26:41 -0500772 responsePtr); // filling up the header here
773 BIOSAttributeValueTable.load(response);
John Wang3ad21752019-10-06 16:42:21 +0800774 return response;
Sampa Misrab37be312019-07-03 02:26:41 -0500775 }
776
John Wang3ad21752019-10-06 16:42:21 +0800777 Table attributeValueTable;
778 Table attributeTable;
779 BIOSAttributeTable.load(attributeTable);
780 traverseBIOSAttrTable(
781 attributeTable,
782 [&BIOSStringTable, &attributeValueTable](
783 const struct pldm_bios_attr_table_entry* tableEntry) {
784 constructAttrValueTableEntry(tableEntry, BIOSStringTable,
785 attributeValueTable);
786 });
787 if (attributeValueTable.empty())
788 {
789 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
790 nxtTransferHandle, transferFlag, nullptr,
791 response.size(), responsePtr);
792 return response;
793 }
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600794 pldm::responder::utils::padAndChecksum(attributeValueTable);
John Wang3ad21752019-10-06 16:42:21 +0800795 BIOSAttributeValueTable.store(attributeValueTable);
796
797 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
798 attributeValueTable.size());
799 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
800 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
801 transferFlag, attributeValueTable.data(),
802 response.size(), responsePtr);
803
Sampa Misrab37be312019-07-03 02:26:41 -0500804 return response;
805}
806
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600807Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength)
Sampa Misrab37be312019-07-03 02:26:41 -0500808{
Deepak Kodihallic3d20892019-08-01 05:38:31 -0500809 fs::create_directory(BIOS_TABLES_DIR);
Sampa Misrab37be312019-07-03 02:26:41 -0500810 auto response = internal::buildBIOSTables(request, payloadLength,
811 BIOS_JSONS_DIR, BIOS_TABLES_DIR);
812
813 return response;
814}
815
John Wang8721ed62019-12-05 14:44:43 +0800816Response Handler::getBIOSAttributeCurrentValueByHandle(const pldm_msg* request,
817 size_t payloadLength)
818{
819 uint32_t transferHandle;
820 uint8_t transferOpFlag;
821 uint16_t attributeHandle;
822
823 auto rc = decode_get_bios_attribute_current_value_by_handle_req(
824 request, payloadLength, &transferHandle, &transferOpFlag,
825 &attributeHandle);
826 if (rc != PLDM_SUCCESS)
827 {
828 return ccOnlyResponse(request, rc);
829 }
830
Deepak Kodihalli4976a682020-01-07 05:48:29 -0600831 fs::path tablesPath(BIOS_TABLES_DIR);
832 auto stringTablePath = tablesPath / stringTableFile;
833 BIOSTable BIOSStringTable(stringTablePath.c_str());
834 auto attrTablePath = tablesPath / attrTableFile;
835 BIOSTable BIOSAttributeTable(attrTablePath.c_str());
836 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty())
837 {
838 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE);
839 }
840
841 auto attrValueTablePath = tablesPath / attrValTableFile;
842 BIOSTable BIOSAttributeValueTable(attrValueTablePath.c_str());
843
844 if (BIOSAttributeValueTable.isEmpty())
845 {
846 Table attributeValueTable;
847 Table attributeTable;
848 BIOSAttributeTable.load(attributeTable);
849 traverseBIOSAttrTable(
850 attributeTable,
851 [&BIOSStringTable, &attributeValueTable](
852 const struct pldm_bios_attr_table_entry* tableEntry) {
853 constructAttrValueTableEntry(tableEntry, BIOSStringTable,
854 attributeValueTable);
855 });
856 if (attributeValueTable.empty())
857 {
858 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE);
859 }
860 pldm::responder::utils::padAndChecksum(attributeValueTable);
861 BIOSAttributeValueTable.store(attributeValueTable);
862 }
John Wang8721ed62019-12-05 14:44:43 +0800863
864 Response table;
Deepak Kodihalli4976a682020-01-07 05:48:29 -0600865 BIOSAttributeValueTable.load(table);
John Wang8721ed62019-12-05 14:44:43 +0800866
867 auto entry = pldm_bios_table_attr_value_find_by_handle(
868 table.data(), table.size(), attributeHandle);
869 if (entry == nullptr)
870 {
871 return ccOnlyResponse(request, PLDM_INVALID_BIOS_ATTR_HANDLE);
872 }
873
874 auto valueLength = pldm_bios_table_attr_value_entry_value_length(entry);
875 auto valuePtr = pldm_bios_table_attr_value_entry_value(entry);
876 Response response(sizeof(pldm_msg_hdr) +
877 PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES +
878 valueLength,
879 0);
880 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
881 encode_get_bios_current_value_by_handle_resp(
882 request->hdr.instance_id, PLDM_SUCCESS, 0, PLDM_START_AND_END, valuePtr,
883 valueLength, responsePtr);
884
885 return response;
886}
887
Sampa Misrab37be312019-07-03 02:26:41 -0500888namespace internal
889{
890
891Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
892 const char* biosJsonDir, const char* biosTablePath)
893{
894 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
895 0);
896 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
897
John Wange96e7e52019-10-05 17:47:30 +0800898 if (setupConfig(biosJsonDir) != 0)
899 {
900 encode_get_bios_table_resp(
901 request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE,
902 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr,
903 response.size(), responsePtr);
904 return response;
905 }
906
Sampa Misrab37be312019-07-03 02:26:41 -0500907 uint32_t transferHandle{};
908 uint8_t transferOpFlag{};
909 uint8_t tableType{};
910
911 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
912 &transferOpFlag, &tableType);
913 if (rc == PLDM_SUCCESS)
914 {
915 BIOSTable BIOSStringTable(
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600916 (std::string(biosTablePath) + "/" + stringTableFile).c_str());
Sampa Misrab37be312019-07-03 02:26:41 -0500917 BIOSTable BIOSAttributeTable(
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600918 (std::string(biosTablePath) + "/" + attrTableFile).c_str());
Sampa Misrab37be312019-07-03 02:26:41 -0500919 BIOSTable BIOSAttributeValueTable(
Deepak Kodihallid9fb1522019-11-28 10:06:34 -0600920 (std::string(biosTablePath) + "/" + attrValTableFile).c_str());
Sampa Misrab37be312019-07-03 02:26:41 -0500921 switch (tableType)
922 {
923 case PLDM_BIOS_STRING_TABLE:
924
John Wange96e7e52019-10-05 17:47:30 +0800925 response = getBIOSStringTable(BIOSStringTable, transferHandle,
926 transferOpFlag,
927 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500928 break;
929 case PLDM_BIOS_ATTR_TABLE:
930
931 if (BIOSStringTable.isEmpty())
932 {
933 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
934 }
935 else
936 {
937 response = getBIOSAttributeTable(
938 BIOSAttributeTable, BIOSStringTable, transferHandle,
939 transferOpFlag, request->hdr.instance_id, biosJsonDir);
940 }
941 break;
942 case PLDM_BIOS_ATTR_VAL_TABLE:
Carol Wangf7d1a362019-11-18 15:34:14 +0800943 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty())
Sampa Misrab37be312019-07-03 02:26:41 -0500944 {
945 rc = PLDM_BIOS_TABLE_UNAVAILABLE;
946 }
947 else
948 {
949 response = getBIOSAttributeValueTable(
950 BIOSAttributeValueTable, BIOSAttributeTable,
951 BIOSStringTable, transferHandle, transferOpFlag,
John Wang3ad21752019-10-06 16:42:21 +0800952 request->hdr.instance_id);
Sampa Misrab37be312019-07-03 02:26:41 -0500953 }
954 break;
955 default:
956 rc = PLDM_INVALID_BIOS_TABLE_TYPE;
957 break;
958 }
959 }
960
961 if (rc != PLDM_SUCCESS)
962 {
963 uint32_t nxtTransferHandle{};
964 uint8_t transferFlag{};
965 size_t respPayloadLength{};
966
967 encode_get_bios_table_resp(request->hdr.instance_id, rc,
968 nxtTransferHandle, transferFlag, nullptr,
969 respPayloadLength, responsePtr);
970 }
971
972 return response;
973}
974
975} // end namespace internal
976} // namespace bios
977
Sampa Misra032bd502019-03-06 05:03:22 -0600978} // namespace responder
979} // namespace pldm