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     try
153     {
154         return getValueIndex(std::get<std::string>(propValue), possibleValues);
155     }
156     catch (const std::exception& e)
157     {
158         return getValueIndex(defaultValue, possibleValues);
159     }
160 }
161 
162 void BIOSEnumAttribute::setAttrValueOnDbus(
163     const pldm_bios_attr_val_table_entry* attrValueEntry,
164     const pldm_bios_attr_table_entry* attrEntry,
165     const BIOSStringTable& stringTable)
166 {
167     if (readOnly || !dBusMap.has_value())
168     {
169         return;
170     }
171     auto [pvHdls, _] = table::attribute::decodeEnumEntry(attrEntry);
172     auto currHdls = table::attribute_value::decodeEnumEntry(attrValueEntry);
173 
174     assert(currHdls.size() == 1);
175     auto valueString = stringTable.findString(pvHdls[currHdls[0]]);
176 
177     auto it = std::find_if(valMap.begin(), valMap.end(),
178                            [&valueString](const auto& typePair) {
179                                return typePair.second == valueString;
180                            });
181     if (it == valMap.end())
182     {
183         return;
184     }
185 
186     dbusHandler->setDbusProperty(*dBusMap, it->first);
187 }
188 
189 void BIOSEnumAttribute::constructEntry(
190     const BIOSStringTable& stringTable, Table& attrTable, Table& attrValueTable,
191     std::optional<std::variant<int64_t, std::string>> optAttributeValue)
192 {
193     auto possibleValuesHandle =
194         getPossibleValuesHandle(stringTable, possibleValues);
195     std::vector<uint8_t> defaultIndices(1, 0);
196     defaultIndices[0] = getValueIndex(defaultValue, possibleValues);
197 
198     pldm_bios_table_attr_entry_enum_info info = {
199         stringTable.findHandle(name),         readOnly,
200         (uint8_t)possibleValuesHandle.size(), possibleValuesHandle.data(),
201         (uint8_t)defaultIndices.size(),       defaultIndices.data(),
202     };
203 
204     auto attrTableEntry =
205         table::attribute::constructEnumEntry(attrTable, &info);
206     auto [attrHandle, attrType, _] =
207         table::attribute::decodeHeader(attrTableEntry);
208 
209     std::vector<uint8_t> currValueIndices(1, 0);
210 
211     if (optAttributeValue.has_value())
212     {
213         auto attributeValue = optAttributeValue.value();
214         if (attributeValue.index() == 1)
215         {
216             auto currValue = std::get<std::string>(attributeValue);
217             currValueIndices[0] = getValueIndex(currValue, possibleValues);
218         }
219         else
220         {
221             currValueIndices[0] = getAttrValueIndex();
222         }
223     }
224     else
225     {
226         currValueIndices[0] = getAttrValueIndex();
227     }
228 
229     table::attribute_value::constructEnumEntry(attrValueTable, attrHandle,
230                                                attrType, currValueIndices);
231 }
232 
233 int BIOSEnumAttribute::updateAttrVal(Table& newValue, uint16_t attrHdl,
234                                      uint8_t attrType,
235                                      const PropertyValue& newPropVal)
236 {
237     auto iter = valMap.find(newPropVal);
238     if (iter == valMap.end())
239     {
240         std::cerr << "Could not find index for new BIOS enum, value="
241                   << std::get<std::string>(newPropVal) << "\n";
242         return PLDM_ERROR;
243     }
244     auto currentValue = iter->second;
245     std::vector<uint8_t> handleIndices{
246         getValueIndex(currentValue, possibleValues)};
247     table::attribute_value::constructEnumEntry(newValue, attrHdl, attrType,
248                                                handleIndices);
249     return PLDM_SUCCESS;
250 }
251 
252 void BIOSEnumAttribute::generateAttributeEntry(
253     const std::variant<int64_t, std::string>& attributevalue,
254     Table& attrValueEntry)
255 {
256     attrValueEntry.resize(sizeof(pldm_bios_attr_val_table_entry) + 1);
257 
258     auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
259         attrValueEntry.data());
260 
261     std::string value = std::get<std::string>(attributevalue);
262     entry->attr_type = 0;
263     entry->value[0] = 1; // number of current values, default 1
264 
265     if (readOnly)
266     {
267         entry->value[1] = getValueIndex(defaultValue, possibleValues);
268     }
269     else
270     {
271         entry->value[1] = getAttrValueIndex(value);
272     }
273 }
274 
275 } // namespace bios
276 } // namespace responder
277 } // namespace pldm
278