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 (!readOnly)
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)
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 void BIOSEnumAttribute::setAttrValueOnDbus(
151     const pldm_bios_attr_val_table_entry* attrValueEntry,
152     const pldm_bios_attr_table_entry* attrEntry,
153     const BIOSStringTable& stringTable)
154 {
155     if (readOnly)
156     {
157         return;
158     }
159     auto [pvHdls, _] = table::attribute::decodeEnumEntry(attrEntry);
160     auto currHdls = table::attribute_value::decodeEnumEntry(attrValueEntry);
161 
162     assert(currHdls.size() == 1);
163 
164     auto valueString = stringTable.findString(pvHdls[currHdls[0]]);
165 
166     auto it = std::find_if(valMap.begin(), valMap.end(),
167                            [&valueString](const auto& typePair) {
168                                return typePair.second == valueString;
169                            });
170     if (it == valMap.end())
171     {
172         return;
173     }
174 
175     dbusHandler->setDbusProperty(*dBusMap, it->first);
176 }
177 
178 void BIOSEnumAttribute::constructEntry(const BIOSStringTable& stringTable,
179                                        Table& attrTable, Table& attrValueTable)
180 {
181     auto possibleValuesHandle =
182         getPossibleValuesHandle(stringTable, possibleValues);
183     std::vector<uint8_t> defaultIndices(1, 0);
184     defaultIndices[0] = getValueIndex(defaultValue, possibleValues);
185 
186     pldm_bios_table_attr_entry_enum_info info = {
187         stringTable.findHandle(name),         readOnly,
188         (uint8_t)possibleValuesHandle.size(), possibleValuesHandle.data(),
189         (uint8_t)defaultIndices.size(),       defaultIndices.data(),
190     };
191 
192     auto attrTableEntry =
193         table::attribute::constructEnumEntry(attrTable, &info);
194     auto [attrHandle, attrType, _] =
195         table::attribute::decodeHeader(attrTableEntry);
196 
197     std::vector<uint8_t> currValueIndices(1, 0);
198     currValueIndices[0] = getAttrValueIndex();
199 
200     table::attribute_value::constructEnumEntry(attrValueTable, attrHandle,
201                                                attrType, currValueIndices);
202 }
203 
204 int BIOSEnumAttribute::updateAttrVal(Table& newValue, uint16_t attrHdl,
205                                      uint8_t attrType,
206                                      const PropertyValue& newPropVal)
207 {
208     auto iter = valMap.find(newPropVal);
209     if (iter == valMap.end())
210     {
211         std::cerr << "Could not find index for new BIOS enum, value="
212                   << std::get<std::string>(newPropVal) << "\n";
213         return PLDM_ERROR;
214     }
215     auto currentValue = iter->second;
216     std::vector<uint8_t> handleIndices{
217         getValueIndex(currentValue, possibleValues)};
218     table::attribute_value::constructEnumEntry(newValue, attrHdl, attrType,
219                                                handleIndices);
220     return PLDM_SUCCESS;
221 }
222 
223 } // namespace bios
224 } // namespace responder
225 } // namespace pldm
226