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