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