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