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