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