1 #include "common/bios_utils.hpp" 2 #include "common/test/mocked_utils.hpp" 3 #include "libpldmresponder/bios_config.hpp" 4 #include "libpldmresponder/bios_string_attribute.hpp" 5 #include "libpldmresponder/oem_handler.hpp" 6 #include "libpldmresponder/platform_config.hpp" 7 #include "mocked_bios.hpp" 8 9 #include <nlohmann/json.hpp> 10 11 #include <fstream> 12 #include <memory> 13 14 #include <gmock/gmock.h> 15 #include <gtest/gtest.h> 16 17 using namespace pldm::bios::utils; 18 using namespace pldm::responder::bios; 19 using namespace pldm::utils; 20 21 using ::testing::_; 22 using ::testing::ElementsAreArray; 23 using ::testing::Return; 24 using ::testing::StrEq; 25 using ::testing::Throw; 26 27 class TestSystemSpecificBIOSConfig : public ::testing::Test 28 { 29 public: 30 static void SetUpTestCase() // will execute once at the beginning of all 31 // TestSystemSpecificBIOSConfig objects 32 { 33 char tmpdir[] = "/tmp/BIOSTables.XXXXXX"; 34 tableDir = fs::path(mkdtemp(tmpdir)); 35 36 std::vector<fs::path> paths = { 37 "./bios_jsons/string_attrs.json", 38 "./bios_jsons/integer_attrs.json", 39 "./bios_jsons/enum_attrs.json", 40 }; 41 42 for (auto& path : paths) 43 { 44 std::ifstream file; 45 file.open(path); 46 auto j = Json::parse(file); 47 jsons.emplace_back(j); 48 } 49 } 50 51 std::optional<Json> findJsonEntry(const std::string& name) 52 { 53 for (auto& json : jsons) 54 { 55 auto entries = json.at("entries"); 56 for (auto& entry : entries) 57 { 58 auto n = entry.at("attribute_name").get<std::string>(); 59 if (n == name) 60 { 61 return entry; 62 } 63 } 64 } 65 return std::nullopt; 66 } 67 68 static void TearDownTestCase() // will be executed once at th end of all 69 // TestSystemSpecificBIOSConfig objects 70 { 71 fs::remove_all(tableDir); 72 } 73 74 static fs::path tableDir; 75 static std::vector<Json> jsons; 76 }; 77 78 fs::path TestSystemSpecificBIOSConfig::tableDir; 79 std::vector<Json> TestSystemSpecificBIOSConfig::jsons; 80 81 class MockSystemConfig : public pldm::responder::platform_config::Handler 82 { 83 public: 84 MockSystemConfig() {} 85 MOCK_METHOD(void, ibmCompatibleAddedCallback, (sdbusplus::message_t&), ()); 86 MOCK_METHOD(std::optional<std::filesystem::path>, getPlatformName, ()); 87 }; 88 89 TEST_F(TestSystemSpecificBIOSConfig, buildTablesTest) 90 { 91 MockdBusHandler dbusHandler; 92 MockSystemConfig mockSystemConfig; 93 std::string biosFilePath("./"); 94 95 EXPECT_CALL(mockSystemConfig, getPlatformName()) 96 .WillOnce(Return(std::filesystem::path("bios_jsons"))); 97 98 BIOSConfig biosConfig(biosFilePath.c_str(), tableDir.c_str(), &dbusHandler, 99 0, 0, nullptr, nullptr, &mockSystemConfig, []() {}); 100 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 101 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 102 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 103 104 EXPECT_TRUE(stringTable); 105 EXPECT_TRUE(attrTable); 106 EXPECT_TRUE(attrValueTable); 107 108 std::set<std::string> expectedStrings = { 109 "HMCManagedState", 110 "On", 111 "Off", 112 "FWBootSide", 113 "Perm", 114 "Temp", 115 "InbandCodeUpdate", 116 "Allowed", 117 "Allowed", 118 "NotAllowed", 119 "CodeUpdatePolicy", 120 "Concurrent", 121 "Disruptive", 122 "VDD_AVSBUS_RAIL", 123 "SBE_IMAGE_MINIMUM_VALID_ECS", 124 "INTEGER_INVALID_CASE", 125 "str_example1", 126 "str_example2", 127 "str_example3"}; 128 std::set<std::string> strings; 129 for (auto entry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>( 130 stringTable->data(), stringTable->size())) 131 { 132 auto str = table::string::decodeString(entry); 133 strings.emplace(str); 134 } 135 136 EXPECT_EQ(strings, expectedStrings); 137 138 BIOSStringTable biosStringTable(*stringTable); 139 140 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 141 attrTable->size())) 142 { 143 auto header = table::attribute::decodeHeader(entry); 144 auto attrName = biosStringTable.findString(header.stringHandle); 145 auto jsonEntry = findJsonEntry(attrName); 146 EXPECT_TRUE(jsonEntry); 147 switch (header.attrType) 148 { 149 case PLDM_BIOS_STRING: 150 case PLDM_BIOS_STRING_READ_ONLY: 151 { 152 auto stringField = table::attribute::decodeStringEntry(entry); 153 auto stringType = BIOSStringAttribute::strTypeMap.at( 154 jsonEntry->at("string_type").get<std::string>()); 155 EXPECT_EQ(stringField.stringType, 156 static_cast<uint8_t>(stringType)); 157 158 EXPECT_EQ( 159 stringField.minLength, 160 jsonEntry->at("minimum_string_length").get<uint16_t>()); 161 EXPECT_EQ( 162 stringField.maxLength, 163 jsonEntry->at("maximum_string_length").get<uint16_t>()); 164 EXPECT_EQ(stringField.defString, 165 jsonEntry->at("default_string").get<std::string>()); 166 EXPECT_EQ(stringField.defLength, 167 (stringField.defString).length()); 168 break; 169 } 170 case PLDM_BIOS_INTEGER: 171 case PLDM_BIOS_INTEGER_READ_ONLY: 172 { 173 auto integerField = table::attribute::decodeIntegerEntry(entry); 174 EXPECT_EQ(integerField.lowerBound, 175 jsonEntry->at("lower_bound").get<uint64_t>()); 176 EXPECT_EQ(integerField.upperBound, 177 jsonEntry->at("upper_bound").get<uint64_t>()); 178 EXPECT_EQ(integerField.scalarIncrement, 179 jsonEntry->at("scalar_increment").get<uint32_t>()); 180 EXPECT_EQ(integerField.defaultValue, 181 jsonEntry->at("default_value").get<uint64_t>()); 182 break; 183 } 184 case PLDM_BIOS_ENUMERATION: 185 case PLDM_BIOS_ENUMERATION_READ_ONLY: 186 { 187 auto [pvHdls, 188 defInds] = table::attribute::decodeEnumEntry(entry); 189 auto possibleValues = jsonEntry->at("possible_values") 190 .get<std::vector<std::string>>(); 191 std::vector<std::string> strings; 192 for (auto pv : pvHdls) 193 { 194 auto s = biosStringTable.findString(pv); 195 strings.emplace_back(s); 196 } 197 EXPECT_EQ(strings, possibleValues); 198 EXPECT_EQ(defInds.size(), 1); 199 200 auto defValue = biosStringTable.findString(pvHdls[defInds[0]]); 201 auto defaultValues = jsonEntry->at("default_values") 202 .get<std::vector<std::string>>(); 203 EXPECT_EQ(defValue, defaultValues[0]); 204 205 break; 206 } 207 default: 208 EXPECT_TRUE(false); 209 break; 210 } 211 } 212 213 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>( 214 attrValueTable->data(), attrValueTable->size())) 215 { 216 auto header = table::attribute_value::decodeHeader(entry); 217 auto attrEntry = 218 table::attribute::findByHandle(*attrTable, header.attrHandle); 219 auto attrHeader = table::attribute::decodeHeader(attrEntry); 220 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 221 auto jsonEntry = findJsonEntry(attrName); 222 EXPECT_TRUE(jsonEntry); 223 switch (header.attrType) 224 { 225 case PLDM_BIOS_STRING: 226 case PLDM_BIOS_STRING_READ_ONLY: 227 { 228 auto value = table::attribute_value::decodeStringEntry(entry); 229 auto defValue = 230 jsonEntry->at("default_string").get<std::string>(); 231 EXPECT_EQ(value, defValue); 232 break; 233 } 234 case PLDM_BIOS_INTEGER: 235 case PLDM_BIOS_INTEGER_READ_ONLY: 236 { 237 auto value = table::attribute_value::decodeIntegerEntry(entry); 238 auto defValue = jsonEntry->at("default_value").get<uint64_t>(); 239 EXPECT_EQ(value, defValue); 240 break; 241 } 242 case PLDM_BIOS_ENUMERATION: 243 case PLDM_BIOS_ENUMERATION_READ_ONLY: 244 { 245 auto indices = table::attribute_value::decodeEnumEntry(entry); 246 EXPECT_EQ(indices.size(), 1); 247 auto possibleValues = jsonEntry->at("possible_values") 248 .get<std::vector<std::string>>(); 249 250 auto defValues = jsonEntry->at("default_values") 251 .get<std::vector<std::string>>(); 252 EXPECT_EQ(possibleValues[indices[0]], defValues[0]); 253 break; 254 } 255 default: 256 EXPECT_TRUE(false); 257 break; 258 } 259 } 260 } 261 262 TEST_F(TestSystemSpecificBIOSConfig, buildTablesSystemSpecificTest) 263 { 264 MockdBusHandler dbusHandler; 265 MockSystemConfig mockSystemConfig; 266 267 EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("")); 268 ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _)) 269 .WillByDefault(Throw(std::exception())); 270 271 BIOSConfig biosConfig("./system_type1/bios_jsons", tableDir.c_str(), 272 &dbusHandler, 0, 0, nullptr, nullptr, 273 &mockSystemConfig, []() {}); 274 275 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 276 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 277 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 278 279 EXPECT_TRUE(stringTable); 280 EXPECT_TRUE(attrTable); 281 EXPECT_TRUE(attrValueTable); 282 283 BIOSStringTable biosStringTable(*stringTable); 284 285 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 286 attrTable->size())) 287 { 288 auto header = table::attribute::decodeHeader(entry); 289 auto attrName = biosStringTable.findString(header.stringHandle); 290 auto jsonEntry = findJsonEntry(attrName); 291 EXPECT_TRUE(jsonEntry); 292 switch (header.attrType) 293 { 294 case PLDM_BIOS_STRING: 295 case PLDM_BIOS_STRING_READ_ONLY: 296 { 297 if (attrName == "str_example2") 298 { 299 auto stringField = 300 table::attribute::decodeStringEntry(entry); 301 EXPECT_EQ(stringField.maxLength, 200); 302 } 303 304 break; 305 } 306 case PLDM_BIOS_INTEGER: 307 case PLDM_BIOS_INTEGER_READ_ONLY: 308 { 309 if (attrName == "SBE_IMAGE_MINIMUM_VALID_ECS") 310 { 311 auto integerField = 312 table::attribute::decodeIntegerEntry(entry); 313 EXPECT_EQ(integerField.upperBound, 30); 314 } 315 break; 316 } 317 case PLDM_BIOS_ENUMERATION: 318 case PLDM_BIOS_ENUMERATION_READ_ONLY: 319 { 320 if (attrName == "FWBootSide") 321 { 322 auto [pvHdls, 323 defInds] = table::attribute::decodeEnumEntry(entry); 324 auto defValue = 325 biosStringTable.findString(pvHdls[defInds[0]]); 326 EXPECT_EQ(defValue, "Temp"); 327 } 328 } 329 } 330 } 331 } 332 333 TEST_F(TestSystemSpecificBIOSConfig, setBIOSTable) 334 { 335 MockdBusHandler dbusHandler; 336 MockSystemConfig mockSystemConfig; 337 338 EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons")); 339 BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr, 340 nullptr, &mockSystemConfig, []() {}); 341 342 std::set<std::string> strings{"pvm_system_name", "pvm_stop_at_standby", 343 "fw_boot_side", "fw_next_boot_side"}; 344 345 Table table; 346 for (const auto& elem : strings) 347 { 348 table::string::constructEntry(table, elem); 349 } 350 351 table::appendPadAndChecksum(table); 352 auto rc = biosConfig.setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 353 EXPECT_EQ(rc, PLDM_SUCCESS); 354 355 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 356 EXPECT_TRUE(stringTable); 357 } 358 359 TEST_F(TestSystemSpecificBIOSConfig, getBIOSTableFailure) 360 { 361 MockdBusHandler dbusHandler; 362 MockSystemConfig mockSystemConfig; 363 364 EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons")); 365 BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr, 366 nullptr, &mockSystemConfig, []() {}); 367 368 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 369 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 370 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 371 372 EXPECT_FALSE(stringTable); 373 EXPECT_FALSE(attrTable); 374 EXPECT_FALSE(attrValueTable); 375 } 376 377 TEST_F(TestSystemSpecificBIOSConfig, setAttrValueFailure) 378 { 379 MockdBusHandler dbusHandler; 380 MockSystemConfig mockSystemConfig; 381 382 EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons")); 383 BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr, 384 nullptr, &mockSystemConfig, []() {}); 385 386 std::vector<uint8_t> attrValueEntry{ 387 0, 0, /* attr handle */ 388 1, /* attr type string read-write */ 389 4, 0, /* current string length */ 390 'a', 'b', 'c', 'd', /* default value string handle index */ 391 }; 392 393 uint16_t attrHandle{10}; 394 attrValueEntry[0] = attrHandle & 0xff; 395 attrValueEntry[1] = (attrHandle >> 8) & 0xff; 396 397 auto rc = biosConfig.setAttrValue(attrValueEntry.data(), 398 attrValueEntry.size(), false); 399 std::cout << "Error in setting Attribute " << rc << std::endl; 400 EXPECT_EQ(rc, PLDM_BIOS_TABLE_UNAVAILABLE); 401 } 402 403 TEST_F(TestSystemSpecificBIOSConfig, setAttrValue) 404 { 405 MockdBusHandler dbusHandler; 406 MockSystemConfig mockSystemConfig; 407 408 EXPECT_CALL(mockSystemConfig, getPlatformName()) 409 .WillOnce(Return(std::filesystem::path(""))); 410 411 BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0, 412 nullptr, nullptr, &mockSystemConfig, []() {}); 413 414 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 415 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 416 417 BIOSStringTable biosStringTable(*stringTable); 418 BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(attrTable->data(), 419 attrTable->size()); 420 auto stringHandle = biosStringTable.findHandle("str_example1"); 421 uint16_t attrHandle{}; 422 423 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 424 attrTable->size())) 425 { 426 auto header = table::attribute::decodeHeader(entry); 427 if (header.stringHandle == stringHandle) 428 { 429 attrHandle = header.attrHandle; 430 break; 431 } 432 } 433 434 EXPECT_NE(attrHandle, 0); 435 436 std::vector<uint8_t> attrValueEntry{ 437 0, 0, /* attr handle */ 438 1, /* attr type string read-write */ 439 4, 0, /* current string length */ 440 'a', 'b', 'c', 'd', /* default value string handle index */ 441 }; 442 443 attrValueEntry[0] = attrHandle & 0xff; 444 attrValueEntry[1] = (attrHandle >> 8) & 0xff; 445 446 DBusMapping dbusMapping{"/xyz/abc/def", 447 "xyz.openbmc_project.str_example1.value", 448 "Str_example1", "string"}; 449 PropertyValue value = std::string("abcd"); 450 EXPECT_CALL(dbusHandler, setDbusProperty(dbusMapping, value)).Times(1); 451 452 auto rc = biosConfig.setAttrValue(attrValueEntry.data(), 453 attrValueEntry.size(), false); 454 EXPECT_EQ(rc, PLDM_SUCCESS); 455 456 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 457 auto findEntry = [&attrValueTable](uint16_t handle) 458 -> const pldm_bios_attr_val_table_entry* { 459 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>( 460 attrValueTable->data(), attrValueTable->size())) 461 { 462 auto [attrHandle, _] = table::attribute_value::decodeHeader(entry); 463 if (attrHandle == handle) 464 return entry; 465 } 466 return nullptr; 467 }; 468 469 auto entry = findEntry(attrHandle); 470 EXPECT_NE(entry, nullptr); 471 472 auto p = reinterpret_cast<const uint8_t*>(entry); 473 EXPECT_THAT(std::vector<uint8_t>(p, p + attrValueEntry.size()), 474 ElementsAreArray(attrValueEntry)); 475 } 476