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