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