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