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