1 #include "bios_enum_attribute.hpp"
2
3 #include "common/utils.hpp"
4
5 #include <phosphor-logging/lg2.hpp>
6
7 PHOSPHOR_LOG2_USING;
8
9 using namespace pldm::utils;
10
11 namespace pldm
12 {
13 namespace responder
14 {
15 namespace bios
16 {
BIOSEnumAttribute(const Json & entry,DBusHandler * const dbusHandler)17 BIOSEnumAttribute::BIOSEnumAttribute(const Json& entry,
18 DBusHandler* const dbusHandler) :
19 BIOSAttribute(entry, dbusHandler)
20 {
21 std::string attrName = entry.at("attribute_name");
22 Json pv = entry.at("possible_values");
23 for (auto& val : pv)
24 {
25 possibleValues.emplace_back(val);
26 }
27
28 std::vector<std::string> defaultValues;
29 Json dv = entry.at("default_values");
30 for (auto& val : dv)
31 {
32 defaultValues.emplace_back(val);
33 }
34
35 Json vdn = entry.at("value_names");
36 for (auto& val : vdn)
37 {
38 valueDisplayNames.emplace_back(val);
39 }
40 assert(defaultValues.size() == 1);
41 defaultValue = defaultValues[0];
42 if (dBusMap.has_value())
43 {
44 auto dbusValues = entry.at("dbus").at("property_values");
45 buildValMap(dbusValues);
46 }
47 }
48
getValueIndex(const std::string & value,const std::vector<std::string> & pVs)49 uint8_t BIOSEnumAttribute::getValueIndex(const std::string& value,
50 const std::vector<std::string>& pVs)
51 {
52 auto iter = std::find_if(pVs.begin(), pVs.end(), [&value](const auto& v) {
53 return v == value;
54 });
55 if (iter == pVs.end())
56 {
57 throw std::invalid_argument("value must be one of possible value");
58 }
59 return iter - pVs.begin();
60 }
61
getPossibleValuesHandle(const BIOSStringTable & stringTable,const std::vector<std::string> & pVs)62 std::vector<uint16_t> BIOSEnumAttribute::getPossibleValuesHandle(
63 const BIOSStringTable& stringTable, const std::vector<std::string>& pVs)
64 {
65 std::vector<uint16_t> possibleValuesHandle;
66 for (const auto& pv : pVs)
67 {
68 auto handle = stringTable.findHandle(pv);
69 possibleValuesHandle.push_back(handle);
70 }
71
72 return possibleValuesHandle;
73 }
74
buildValMap(const Json & dbusVals)75 void BIOSEnumAttribute::buildValMap(const Json& dbusVals)
76 {
77 PropertyValue value;
78 size_t pos = 0;
79 for (auto it = dbusVals.begin(); it != dbusVals.end(); ++it, ++pos)
80 {
81 if (dBusMap->propertyType == "uint8_t")
82 {
83 value = static_cast<uint8_t>(it.value());
84 }
85 else if (dBusMap->propertyType == "uint16_t")
86 {
87 value = static_cast<uint16_t>(it.value());
88 }
89 else if (dBusMap->propertyType == "uint32_t")
90 {
91 value = static_cast<uint32_t>(it.value());
92 }
93 else if (dBusMap->propertyType == "uint64_t")
94 {
95 value = static_cast<uint64_t>(it.value());
96 }
97 else if (dBusMap->propertyType == "int16_t")
98 {
99 value = static_cast<int16_t>(it.value());
100 }
101 else if (dBusMap->propertyType == "int32_t")
102 {
103 value = static_cast<int32_t>(it.value());
104 }
105 else if (dBusMap->propertyType == "int64_t")
106 {
107 value = static_cast<int64_t>(it.value());
108 }
109 else if (dBusMap->propertyType == "bool")
110 {
111 value = static_cast<bool>(it.value());
112 }
113 else if (dBusMap->propertyType == "double")
114 {
115 value = static_cast<double>(it.value());
116 }
117 else if (dBusMap->propertyType == "string")
118 {
119 value = static_cast<std::string>(it.value());
120 }
121 else
122 {
123 error("Unknown D-Bus property type '{TYPE}'", "TYPE",
124 dBusMap->propertyType);
125 throw std::invalid_argument("Unknown D-BUS property type");
126 }
127 valMap.emplace(value, possibleValues[pos]);
128 }
129 }
130
getAttrValueIndex()131 uint8_t BIOSEnumAttribute::getAttrValueIndex()
132 {
133 auto defaultValueIndex = getValueIndex(defaultValue, possibleValues);
134 if (!dBusMap.has_value())
135 {
136 return defaultValueIndex;
137 }
138
139 try
140 {
141 auto propValue = dbusHandler->getDbusPropertyVariant(
142 dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
143 dBusMap->interface.c_str());
144 auto iter = valMap.find(propValue);
145 if (iter == valMap.end())
146 {
147 return defaultValueIndex;
148 }
149 auto currentValue = iter->second;
150 return getValueIndex(currentValue, possibleValues);
151 }
152 catch (const std::exception&)
153 {
154 return defaultValueIndex;
155 }
156 }
157
getAttrValueIndex(const PropertyValue & propValue)158 uint8_t BIOSEnumAttribute::getAttrValueIndex(const PropertyValue& propValue)
159 {
160 try
161 {
162 return getValueIndex(std::get<std::string>(propValue), possibleValues);
163 }
164 catch (const std::exception&)
165 {
166 return getValueIndex(defaultValue, possibleValues);
167 }
168 }
169
setAttrValueOnDbus(const pldm_bios_attr_val_table_entry * attrValueEntry,const pldm_bios_attr_table_entry * attrEntry,const BIOSStringTable & stringTable)170 void BIOSEnumAttribute::setAttrValueOnDbus(
171 const pldm_bios_attr_val_table_entry* attrValueEntry,
172 const pldm_bios_attr_table_entry* attrEntry,
173 const BIOSStringTable& stringTable)
174 {
175 if (!dBusMap.has_value())
176 {
177 return;
178 }
179 auto [pvHdls, _] = table::attribute::decodeEnumEntry(attrEntry);
180 auto currHdls = table::attribute_value::decodeEnumEntry(attrValueEntry);
181
182 assert(currHdls.size() == 1);
183 auto valueString = stringTable.findString(pvHdls[currHdls[0]]);
184
185 auto it = std::find_if(valMap.begin(), valMap.end(),
186 [&valueString](const auto& typePair) {
187 return typePair.second == valueString;
188 });
189 if (it == valMap.end())
190 {
191 return;
192 }
193
194 dbusHandler->setDbusProperty(*dBusMap, it->first);
195 }
196
populateValueDisplayNamesMap(uint16_t attrHandle)197 void BIOSEnumAttribute::populateValueDisplayNamesMap(uint16_t attrHandle)
198 {
199 for (auto& vdn : valueDisplayNames)
200 {
201 valueDisplayNamesMap[attrHandle].push_back(vdn);
202 }
203 }
204
constructEntry(const BIOSStringTable & stringTable,Table & attrTable,Table & attrValueTable,std::optional<std::variant<int64_t,std::string>> optAttributeValue)205 void BIOSEnumAttribute::constructEntry(
206 const BIOSStringTable& stringTable, Table& attrTable, Table& attrValueTable,
207 std::optional<std::variant<int64_t, std::string>> optAttributeValue)
208 {
209 auto possibleValuesHandle =
210 getPossibleValuesHandle(stringTable, possibleValues);
211 std::vector<uint8_t> defaultIndices(1, 0);
212 defaultIndices[0] = getValueIndex(defaultValue, possibleValues);
213
214 pldm_bios_table_attr_entry_enum_info info = {
215 stringTable.findHandle(name), readOnly,
216 (uint8_t)possibleValuesHandle.size(), possibleValuesHandle.data(),
217 (uint8_t)defaultIndices.size(), defaultIndices.data()};
218
219 auto attrTableEntry =
220 table::attribute::constructEnumEntry(attrTable, &info);
221 auto [attrHandle, attrType,
222 _] = table::attribute::decodeHeader(attrTableEntry);
223
224 populateValueDisplayNamesMap(attrHandle);
225
226 std::vector<uint8_t> currValueIndices(1, 0);
227
228 if (optAttributeValue.has_value())
229 {
230 auto attributeValue = optAttributeValue.value();
231 if (attributeValue.index() == 1)
232 {
233 auto currValue = std::get<std::string>(attributeValue);
234 currValueIndices[0] = getValueIndex(currValue, possibleValues);
235 }
236 else
237 {
238 currValueIndices[0] = getAttrValueIndex();
239 }
240 }
241 else
242 {
243 currValueIndices[0] = getAttrValueIndex();
244 }
245
246 table::attribute_value::constructEnumEntry(attrValueTable, attrHandle,
247 attrType, currValueIndices);
248 }
249
updateAttrVal(Table & newValue,uint16_t attrHdl,uint8_t attrType,const PropertyValue & newPropVal)250 int BIOSEnumAttribute::updateAttrVal(Table& newValue, uint16_t attrHdl,
251 uint8_t attrType,
252 const PropertyValue& newPropVal)
253 {
254 auto iter = valMap.find(newPropVal);
255 if (iter == valMap.end())
256 {
257 error("Failed to find index for new BIOS enum value '{VALUE}'", "VALUE",
258 std::get<std::string>(newPropVal));
259 return PLDM_ERROR;
260 }
261 auto currentValue = iter->second;
262 std::vector<uint8_t> handleIndices{
263 getValueIndex(currentValue, possibleValues)};
264 table::attribute_value::constructEnumEntry(newValue, attrHdl, attrType,
265 handleIndices);
266 return PLDM_SUCCESS;
267 }
268
generateAttributeEntry(const std::variant<int64_t,std::string> & attributevalue,Table & attrValueEntry)269 void BIOSEnumAttribute::generateAttributeEntry(
270 const std::variant<int64_t, std::string>& attributevalue,
271 Table& attrValueEntry)
272 {
273 attrValueEntry.resize(sizeof(pldm_bios_attr_val_table_entry) + 1);
274
275 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
276 attrValueEntry.data());
277
278 std::string value = std::get<std::string>(attributevalue);
279 entry->attr_type = 0;
280 entry->value[0] = 1; // number of current values, default 1
281 entry->value[1] = getAttrValueIndex(value);
282 }
283
284 } // namespace bios
285 } // namespace responder
286 } // namespace pldm
287