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