1 #include "bios_config.hpp" 2 3 #include "bios_enum_attribute.hpp" 4 #include "bios_integer_attribute.hpp" 5 #include "bios_string_attribute.hpp" 6 #include "bios_table.hpp" 7 8 #include <fstream> 9 #include <iostream> 10 11 namespace pldm 12 { 13 namespace responder 14 { 15 namespace bios 16 { 17 namespace 18 { 19 20 constexpr auto enumJsonFile = "enum_attrs.json"; 21 constexpr auto stringJsonFile = "string_attrs.json"; 22 constexpr auto integerJsonFile = "integer_attrs.json"; 23 24 constexpr auto stringTableFile = "stringTable"; 25 constexpr auto attrTableFile = "attributeTable"; 26 constexpr auto attrValueTableFile = "attributeValueTable"; 27 28 } // namespace 29 30 BIOSConfig::BIOSConfig(const char* jsonDir, const char* tableDir, 31 DBusHandler* const dbusHandler) : 32 jsonDir(jsonDir), 33 tableDir(tableDir), dbusHandler(dbusHandler) 34 { 35 fs::create_directories(tableDir); 36 constructAttributes(); 37 } 38 39 void BIOSConfig::buildTables() 40 { 41 auto stringTable = buildAndStoreStringTable(); 42 if (stringTable) 43 { 44 buildAndStoreAttrTables(*stringTable); 45 } 46 } 47 48 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType) 49 { 50 fs::path tablePath; 51 switch (tableType) 52 { 53 case PLDM_BIOS_STRING_TABLE: 54 tablePath = tableDir / stringTableFile; 55 break; 56 case PLDM_BIOS_ATTR_TABLE: 57 tablePath = tableDir / attrTableFile; 58 break; 59 case PLDM_BIOS_ATTR_VAL_TABLE: 60 tablePath = tableDir / attrValueTableFile; 61 break; 62 } 63 return loadTable(tablePath); 64 } 65 66 void BIOSConfig::constructAttributes() 67 { 68 load(jsonDir / stringJsonFile, [this](const Json& entry) { 69 constructAttribute<BIOSStringAttribute>(entry); 70 }); 71 load(jsonDir / integerJsonFile, [this](const Json& entry) { 72 constructAttribute<BIOSIntegerAttribute>(entry); 73 }); 74 load(jsonDir / enumJsonFile, [this](const Json& entry) { 75 constructAttribute<BIOSEnumAttribute>(entry); 76 }); 77 } 78 79 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable) 80 { 81 BIOSStringTable biosStringTable(stringTable); 82 83 if (biosAttributes.empty()) 84 { 85 return; 86 } 87 88 Table attrTable, attrValueTable; 89 90 for (auto& attr : biosAttributes) 91 { 92 try 93 { 94 attr->constructEntry(biosStringTable, attrTable, attrValueTable); 95 } 96 catch (const std::exception& e) 97 { 98 std::cerr << "Construct Table Entry Error, AttributeName = " 99 << attr->name << std::endl; 100 } 101 } 102 103 table::appendPadAndChecksum(attrTable); 104 table::appendPadAndChecksum(attrValueTable); 105 106 storeTable(tableDir / attrTableFile, attrTable); 107 storeTable(tableDir / attrValueTableFile, attrValueTable); 108 } 109 110 std::optional<Table> BIOSConfig::buildAndStoreStringTable() 111 { 112 std::set<std::string> strings; 113 auto handler = [&strings](const Json& entry) { 114 strings.emplace(entry.at("attribute_name")); 115 }; 116 117 load(jsonDir / stringJsonFile, handler); 118 load(jsonDir / integerJsonFile, handler); 119 load(jsonDir / enumJsonFile, [&strings](const Json& entry) { 120 strings.emplace(entry.at("attribute_name")); 121 auto possibleValues = entry.at("possible_values"); 122 for (auto& pv : possibleValues) 123 { 124 strings.emplace(pv); 125 } 126 }); 127 128 if (strings.empty()) 129 { 130 return std::nullopt; 131 } 132 133 Table table; 134 for (const auto& elem : strings) 135 { 136 table::string::constructEntry(table, elem); 137 } 138 139 table::appendPadAndChecksum(table); 140 storeTable(tableDir / stringTableFile, table); 141 return table; 142 } 143 144 void BIOSConfig::storeTable(const fs::path& path, const Table& table) 145 { 146 BIOSTable biosTable(path.c_str()); 147 biosTable.store(table); 148 } 149 150 std::optional<Table> BIOSConfig::loadTable(const fs::path& path) 151 { 152 BIOSTable biosTable(path.c_str()); 153 if (biosTable.isEmpty()) 154 { 155 return std::nullopt; 156 } 157 158 Table table; 159 biosTable.load(table); 160 return table; 161 } 162 163 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler) 164 { 165 std::ifstream file; 166 Json jsonConf; 167 if (fs::exists(filePath)) 168 { 169 try 170 { 171 file.open(filePath); 172 jsonConf = Json::parse(file); 173 auto entries = jsonConf.at("entries"); 174 for (auto& entry : entries) 175 { 176 try 177 { 178 handler(entry); 179 } 180 catch (const std::exception& e) 181 { 182 std::cerr 183 << "Failed to parse JSON config file(entry handler) : " 184 << filePath.c_str() << ", " << e.what() << std::endl; 185 } 186 } 187 } 188 catch (const std::exception& e) 189 { 190 std::cerr << "Failed to parse JSON config file : " 191 << filePath.c_str() << std::endl; 192 } 193 } 194 } 195 196 int BIOSConfig::checkAttrValueToUpdate( 197 const pldm_bios_attr_val_table_entry* attrValueEntry, 198 const pldm_bios_attr_table_entry* attrEntry, Table&) 199 200 { 201 auto [attrHandle, attrType] = 202 table::attribute_value::decodeHeader(attrValueEntry); 203 204 switch (attrType) 205 { 206 case PLDM_BIOS_ENUMERATION: 207 { 208 auto value = 209 table::attribute_value::decodeEnumEntry(attrValueEntry); 210 auto [pvHdls, defIndex] = 211 table::attribute::decodeEnumEntry(attrEntry); 212 assert(value.size() == 1); 213 if (value[0] >= pvHdls.size()) 214 { 215 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0] 216 << std::endl; 217 return PLDM_ERROR_INVALID_DATA; 218 } 219 220 return PLDM_SUCCESS; 221 } 222 case PLDM_BIOS_INTEGER: 223 { 224 auto value = 225 table::attribute_value::decodeIntegerEntry(attrValueEntry); 226 auto [lower, upper, scalar, def] = 227 table::attribute::decodeIntegerEntry(attrEntry); 228 229 if (value < lower || value > upper) 230 { 231 std::cerr << "Integer: out of bound, value = " << value 232 << std::endl; 233 return PLDM_ERROR_INVALID_DATA; 234 } 235 return PLDM_SUCCESS; 236 } 237 case PLDM_BIOS_STRING: 238 { 239 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 240 auto value = 241 table::attribute_value::decodeStringEntry(attrValueEntry); 242 if (value.size() < stringConf.minLength || 243 value.size() > stringConf.maxLength) 244 { 245 std::cerr << "String: Length error, string = " << value 246 << " length = " << value.size() << std::endl; 247 return PLDM_ERROR_INVALID_LENGTH; 248 } 249 return PLDM_SUCCESS; 250 } 251 default: 252 std::cerr << "ReadOnly or Unspported type, type = " << attrType 253 << std::endl; 254 return PLDM_ERROR; 255 }; 256 } 257 258 int BIOSConfig::setAttrValue(const void* entry, size_t size) 259 { 260 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 261 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 262 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 263 if (!attrValueTable || !attrTable || !stringTable) 264 { 265 return PLDM_BIOS_TABLE_UNAVAILABLE; 266 } 267 268 auto attrValueEntry = 269 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 270 271 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 272 273 auto attrEntry = 274 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle); 275 if (!attrEntry) 276 { 277 return PLDM_ERROR; 278 } 279 280 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 281 if (rc != PLDM_SUCCESS) 282 { 283 return rc; 284 } 285 286 auto destTable = 287 table::attribute_value::updateTable(*attrValueTable, entry, size); 288 289 if (!destTable) 290 { 291 return PLDM_ERROR; 292 } 293 294 try 295 { 296 auto attrHeader = table::attribute::decodeHeader(attrEntry); 297 298 BIOSStringTable biosStringTable(*stringTable); 299 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 300 301 auto iter = std::find_if( 302 biosAttributes.begin(), biosAttributes.end(), 303 [&attrName](const auto& attr) { return attr->name == attrName; }); 304 305 if (iter == biosAttributes.end()) 306 { 307 return PLDM_ERROR; 308 } 309 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, biosStringTable); 310 } 311 catch (const std::exception& e) 312 { 313 std::cerr << "Set attribute value error: " << e.what() << std::endl; 314 return PLDM_ERROR; 315 } 316 317 BIOSTable biosAttrValueTable((tableDir / attrValueTableFile).c_str()); 318 biosAttrValueTable.store(*destTable); 319 return PLDM_SUCCESS; 320 } 321 322 void BIOSConfig::removeTables() 323 { 324 try 325 { 326 fs::remove(tableDir / stringTableFile); 327 fs::remove(tableDir / attrTableFile); 328 fs::remove(tableDir / attrValueTableFile); 329 } 330 catch (const std::exception& e) 331 { 332 std::cerr << "Remove the tables error: " << e.what() << std::endl; 333 } 334 } 335 336 void BIOSConfig::processBiosAttrChangeNotification( 337 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex) 338 { 339 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap(); 340 const auto& propertyName = dBusMap->propertyName; 341 const auto& attrName = biosAttributes[biosAttrIndex]->name; 342 343 const auto it = chProperties.find(propertyName); 344 if (it == chProperties.end()) 345 { 346 return; 347 } 348 349 PropertyValue newPropVal = it->second; 350 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 351 if (!stringTable.has_value()) 352 { 353 std::cerr << "BIOS string table unavailable\n"; 354 return; 355 } 356 BIOSStringTable biosStringTable(*stringTable); 357 uint16_t attrNameHdl{}; 358 try 359 { 360 attrNameHdl = biosStringTable.findHandle(attrName); 361 } 362 catch (std::invalid_argument& e) 363 { 364 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE=" 365 << attrName.c_str() << "\n"; 366 return; 367 } 368 369 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 370 if (!attrTable.has_value()) 371 { 372 std::cerr << "Attribute table not present\n"; 373 return; 374 } 375 const struct pldm_bios_attr_table_entry* tableEntry = 376 table::attribute::findByStringHandle(*attrTable, attrNameHdl); 377 if (tableEntry == nullptr) 378 { 379 std::cerr << "Attribute not found in attribute table, name= " 380 << attrName.c_str() << "name handle=" << attrNameHdl << "\n"; 381 return; 382 } 383 384 auto [attrHdl, attrType, stringHdl] = 385 table::attribute::decodeHeader(tableEntry); 386 387 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 388 389 if (!attrValueSrcTable.has_value()) 390 { 391 std::cerr << "Attribute value table not present\n"; 392 return; 393 } 394 395 Table newValue; 396 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal( 397 newValue, attrHdl, attrType, newPropVal); 398 if (rc != PLDM_SUCCESS) 399 { 400 std::cerr << "Could not update the attribute value table for attribute " 401 "handle=" 402 << attrHdl << " and type=" << (uint32_t)attrType << "\n"; 403 return; 404 } 405 auto destTable = table::attribute_value::updateTable( 406 *attrValueSrcTable, newValue.data(), newValue.size()); 407 if (destTable.has_value()) 408 { 409 storeTable(tableDir / attrValueTableFile, *destTable); 410 } 411 } 412 413 } // namespace bios 414 } // namespace responder 415 } // namespace pldm 416