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(const BIOSStringTable& stringTable,
199                                        Table& attrTable, Table& attrValueTable)
200 {
201     auto possibleValuesHandle =
202         getPossibleValuesHandle(stringTable, possibleValues);
203     std::vector<uint8_t> defaultIndices(1, 0);
204     defaultIndices[0] = getValueIndex(defaultValue, possibleValues);
205 
206     pldm_bios_table_attr_entry_enum_info info = {
207         stringTable.findHandle(name),         readOnly,
208         (uint8_t)possibleValuesHandle.size(), possibleValuesHandle.data(),
209         (uint8_t)defaultIndices.size(),       defaultIndices.data(),
210     };
211 
212     auto attrTableEntry =
213         table::attribute::constructEnumEntry(attrTable, &info);
214     auto [attrHandle, attrType, _] =
215         table::attribute::decodeHeader(attrTableEntry);
216 
217     std::vector<uint8_t> currValueIndices(1, 0);
218     currValueIndices[0] = getAttrValueIndex();
219 
220     table::attribute_value::constructEnumEntry(attrValueTable, attrHandle,
221                                                attrType, currValueIndices);
222 }
223 
224 int BIOSEnumAttribute::updateAttrVal(Table& newValue, uint16_t attrHdl,
225                                      uint8_t attrType,
226                                      const PropertyValue& newPropVal)
227 {
228     auto iter = valMap.find(newPropVal);
229     if (iter == valMap.end())
230     {
231         std::cerr << "Could not find index for new BIOS enum, value="
232                   << std::get<std::string>(newPropVal) << "\n";
233         return PLDM_ERROR;
234     }
235     auto currentValue = iter->second;
236     std::vector<uint8_t> handleIndices{
237         getValueIndex(currentValue, possibleValues)};
238     table::attribute_value::constructEnumEntry(newValue, attrHdl, attrType,
239                                                handleIndices);
240     return PLDM_SUCCESS;
241 }
242 
243 void BIOSEnumAttribute::generateAttributeEntry(
244     const std::variant<int64_t, std::string>& attributevalue,
245     Table& attrValueEntry)
246 {
247     attrValueEntry.resize(sizeof(pldm_bios_attr_val_table_entry) + 1);
248 
249     auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
250         attrValueEntry.data());
251 
252     std::string value = std::get<std::string>(attributevalue);
253     entry->attr_type = 0;
254     entry->value[0] = 1; // number of current values, default 1
255 
256     if (readOnly)
257     {
258         entry->value[1] = getValueIndex(defaultValue, possibleValues);
259     }
260     else if (!dBusMap.has_value())
261     {
262         entry->value[1] = getValueIndex(value, possibleValues);
263     }
264     else
265     {
266         entry->value[1] = getAttrValueIndex(value);
267     }
268 }
269 
270 } // namespace bios
271 } // namespace responder
272 } // namespace pldm
273