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 = {"HMCManagedState", 109 "On", 110 "Off", 111 "FWBootSide", 112 "Perm", 113 "Temp", 114 "InbandCodeUpdate", 115 "Allowed", 116 "Allowed", 117 "NotAllowed", 118 "CodeUpdatePolicy", 119 "Concurrent", 120 "Disruptive", 121 "VDD_AVSBUS_RAIL", 122 "SBE_IMAGE_MINIMUM_VALID_ECS", 123 "INTEGER_INVALID_CASE", 124 "str_example1", 125 "str_example2", 126 "str_example3"}; 127 std::set<std::string> strings; 128 for (auto entry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>( 129 stringTable->data(), stringTable->size())) 130 { 131 auto str = table::string::decodeString(entry); 132 strings.emplace(str); 133 } 134 135 EXPECT_EQ(strings, expectedStrings); 136 137 BIOSStringTable biosStringTable(*stringTable); 138 139 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 140 attrTable->size())) 141 { 142 auto header = table::attribute::decodeHeader(entry); 143 auto attrName = biosStringTable.findString(header.stringHandle); 144 auto jsonEntry = findJsonEntry(attrName); 145 EXPECT_TRUE(jsonEntry); 146 switch (header.attrType) 147 { 148 case PLDM_BIOS_STRING: 149 case PLDM_BIOS_STRING_READ_ONLY: 150 { 151 auto stringField = table::attribute::decodeStringEntry(entry); 152 auto stringType = BIOSStringAttribute::strTypeMap.at( 153 jsonEntry->at("string_type").get<std::string>()); 154 EXPECT_EQ(stringField.stringType, 155 static_cast<uint8_t>(stringType)); 156 157 EXPECT_EQ( 158 stringField.minLength, 159 jsonEntry->at("minimum_string_length").get<uint16_t>()); 160 EXPECT_EQ( 161 stringField.maxLength, 162 jsonEntry->at("maximum_string_length").get<uint16_t>()); 163 EXPECT_EQ(stringField.defString, 164 jsonEntry->at("default_string").get<std::string>()); 165 EXPECT_EQ(stringField.defLength, 166 (stringField.defString).length()); 167 break; 168 } 169 case PLDM_BIOS_INTEGER: 170 case PLDM_BIOS_INTEGER_READ_ONLY: 171 { 172 auto integerField = table::attribute::decodeIntegerEntry(entry); 173 EXPECT_EQ(integerField.lowerBound, 174 jsonEntry->at("lower_bound").get<uint64_t>()); 175 EXPECT_EQ(integerField.upperBound, 176 jsonEntry->at("upper_bound").get<uint64_t>()); 177 EXPECT_EQ(integerField.scalarIncrement, 178 jsonEntry->at("scalar_increment").get<uint32_t>()); 179 EXPECT_EQ(integerField.defaultValue, 180 jsonEntry->at("default_value").get<uint64_t>()); 181 break; 182 } 183 case PLDM_BIOS_ENUMERATION: 184 case PLDM_BIOS_ENUMERATION_READ_ONLY: 185 { 186 auto [pvHdls, 187 defInds] = table::attribute::decodeEnumEntry(entry); 188 auto possibleValues = jsonEntry->at("possible_values") 189 .get<std::vector<std::string>>(); 190 std::vector<std::string> strings; 191 for (auto pv : pvHdls) 192 { 193 auto s = biosStringTable.findString(pv); 194 strings.emplace_back(s); 195 } 196 EXPECT_EQ(strings, possibleValues); 197 EXPECT_EQ(defInds.size(), 1); 198 199 auto defValue = biosStringTable.findString(pvHdls[defInds[0]]); 200 auto defaultValues = jsonEntry->at("default_values") 201 .get<std::vector<std::string>>(); 202 EXPECT_EQ(defValue, defaultValues[0]); 203 204 break; 205 } 206 default: 207 EXPECT_TRUE(false); 208 break; 209 } 210 } 211 212 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>( 213 attrValueTable->data(), attrValueTable->size())) 214 { 215 auto header = table::attribute_value::decodeHeader(entry); 216 auto attrEntry = table::attribute::findByHandle(*attrTable, 217 header.attrHandle); 218 auto attrHeader = table::attribute::decodeHeader(attrEntry); 219 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 220 auto jsonEntry = findJsonEntry(attrName); 221 EXPECT_TRUE(jsonEntry); 222 switch (header.attrType) 223 { 224 case PLDM_BIOS_STRING: 225 case PLDM_BIOS_STRING_READ_ONLY: 226 { 227 auto value = table::attribute_value::decodeStringEntry(entry); 228 auto defValue = 229 jsonEntry->at("default_string").get<std::string>(); 230 EXPECT_EQ(value, defValue); 231 break; 232 } 233 case PLDM_BIOS_INTEGER: 234 case PLDM_BIOS_INTEGER_READ_ONLY: 235 { 236 auto value = table::attribute_value::decodeIntegerEntry(entry); 237 auto defValue = jsonEntry->at("default_value").get<uint64_t>(); 238 EXPECT_EQ(value, defValue); 239 break; 240 } 241 case PLDM_BIOS_ENUMERATION: 242 case PLDM_BIOS_ENUMERATION_READ_ONLY: 243 { 244 auto indices = table::attribute_value::decodeEnumEntry(entry); 245 EXPECT_EQ(indices.size(), 1); 246 auto possibleValues = jsonEntry->at("possible_values") 247 .get<std::vector<std::string>>(); 248 249 auto defValues = jsonEntry->at("default_values") 250 .get<std::vector<std::string>>(); 251 EXPECT_EQ(possibleValues[indices[0]], defValues[0]); 252 break; 253 } 254 default: 255 EXPECT_TRUE(false); 256 break; 257 } 258 } 259 } 260 261 TEST_F(TestSystemSpecificBIOSConfig, buildTablesSystemSpecificTest) 262 { 263 MockdBusHandler dbusHandler; 264 MockSystemConfig mockSystemConfig; 265 266 EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("")); 267 ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _)) 268 .WillByDefault(Throw(std::exception())); 269 270 BIOSConfig biosConfig("./system_type1/bios_jsons", tableDir.c_str(), 271 &dbusHandler, 0, 0, nullptr, nullptr, 272 &mockSystemConfig, []() {}); 273 274 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 275 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 276 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 277 278 EXPECT_TRUE(stringTable); 279 EXPECT_TRUE(attrTable); 280 EXPECT_TRUE(attrValueTable); 281 282 BIOSStringTable biosStringTable(*stringTable); 283 284 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 285 attrTable->size())) 286 { 287 auto header = table::attribute::decodeHeader(entry); 288 auto attrName = biosStringTable.findString(header.stringHandle); 289 auto jsonEntry = findJsonEntry(attrName); 290 EXPECT_TRUE(jsonEntry); 291 switch (header.attrType) 292 { 293 case PLDM_BIOS_STRING: 294 case PLDM_BIOS_STRING_READ_ONLY: 295 { 296 if (attrName == "str_example2") 297 { 298 auto stringField = 299 table::attribute::decodeStringEntry(entry); 300 EXPECT_EQ(stringField.maxLength, 200); 301 } 302 303 break; 304 } 305 case PLDM_BIOS_INTEGER: 306 case PLDM_BIOS_INTEGER_READ_ONLY: 307 { 308 if (attrName == "SBE_IMAGE_MINIMUM_VALID_ECS") 309 { 310 auto integerField = 311 table::attribute::decodeIntegerEntry(entry); 312 EXPECT_EQ(integerField.upperBound, 30); 313 } 314 break; 315 } 316 case PLDM_BIOS_ENUMERATION: 317 case PLDM_BIOS_ENUMERATION_READ_ONLY: 318 { 319 if (attrName == "FWBootSide") 320 { 321 auto [pvHdls, 322 defInds] = table::attribute::decodeEnumEntry(entry); 323 auto defValue = 324 biosStringTable.findString(pvHdls[defInds[0]]); 325 EXPECT_EQ(defValue, "Temp"); 326 } 327 } 328 } 329 } 330 } 331 332 TEST_F(TestSystemSpecificBIOSConfig, setBIOSTable) 333 { 334 MockdBusHandler dbusHandler; 335 MockSystemConfig mockSystemConfig; 336 337 EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons")); 338 BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr, 339 nullptr, &mockSystemConfig, []() {}); 340 341 std::set<std::string> strings{"pvm_system_name", "pvm_stop_at_standby", 342 "fw_boot_side", "fw_next_boot_side"}; 343 344 Table table; 345 for (const auto& elem : strings) 346 { 347 table::string::constructEntry(table, elem); 348 } 349 350 table::appendPadAndChecksum(table); 351 auto rc = biosConfig.setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 352 EXPECT_EQ(rc, PLDM_SUCCESS); 353 354 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 355 EXPECT_TRUE(stringTable); 356 } 357 358 TEST_F(TestSystemSpecificBIOSConfig, getBIOSTableFailure) 359 { 360 MockdBusHandler dbusHandler; 361 MockSystemConfig mockSystemConfig; 362 363 EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons")); 364 BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr, 365 nullptr, &mockSystemConfig, []() {}); 366 367 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 368 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 369 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 370 371 EXPECT_FALSE(stringTable); 372 EXPECT_FALSE(attrTable); 373 EXPECT_FALSE(attrValueTable); 374 } 375 376 TEST_F(TestSystemSpecificBIOSConfig, setAttrValueFailure) 377 { 378 MockdBusHandler dbusHandler; 379 MockSystemConfig mockSystemConfig; 380 381 EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons")); 382 BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr, 383 nullptr, &mockSystemConfig, []() {}); 384 385 std::vector<uint8_t> attrValueEntry{ 386 0, 0, /* attr handle */ 387 1, /* attr type string read-write */ 388 4, 0, /* current string length */ 389 'a', 'b', 'c', 'd', /* default value string handle index */ 390 }; 391 392 uint16_t attrHandle{10}; 393 attrValueEntry[0] = attrHandle & 0xff; 394 attrValueEntry[1] = (attrHandle >> 8) & 0xff; 395 396 auto rc = biosConfig.setAttrValue(attrValueEntry.data(), 397 attrValueEntry.size(), false); 398 std::cout << "Error in setting Attribute " << rc << std::endl; 399 EXPECT_EQ(rc, PLDM_BIOS_TABLE_UNAVAILABLE); 400 } 401 402 TEST_F(TestSystemSpecificBIOSConfig, setAttrValue) 403 { 404 MockdBusHandler dbusHandler; 405 MockSystemConfig mockSystemConfig; 406 407 EXPECT_CALL(mockSystemConfig, getPlatformName()) 408 .WillOnce(Return(std::filesystem::path(""))); 409 410 BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0, 411 nullptr, nullptr, &mockSystemConfig, []() {}); 412 413 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 414 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 415 416 BIOSStringTable biosStringTable(*stringTable); 417 BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(attrTable->data(), 418 attrTable->size()); 419 auto stringHandle = biosStringTable.findHandle("str_example1"); 420 uint16_t attrHandle{}; 421 422 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 423 attrTable->size())) 424 { 425 auto header = table::attribute::decodeHeader(entry); 426 if (header.stringHandle == stringHandle) 427 { 428 attrHandle = header.attrHandle; 429 break; 430 } 431 } 432 433 EXPECT_NE(attrHandle, 0); 434 435 std::vector<uint8_t> attrValueEntry{ 436 0, 0, /* attr handle */ 437 1, /* attr type string read-write */ 438 4, 0, /* current string length */ 439 'a', 'b', 'c', 'd', /* default value string handle index */ 440 }; 441 442 attrValueEntry[0] = attrHandle & 0xff; 443 attrValueEntry[1] = (attrHandle >> 8) & 0xff; 444 445 DBusMapping dbusMapping{"/xyz/abc/def", 446 "xyz.openbmc_project.str_example1.value", 447 "Str_example1", "string"}; 448 PropertyValue value = std::string("abcd"); 449 EXPECT_CALL(dbusHandler, setDbusProperty(dbusMapping, value)).Times(1); 450 451 auto rc = biosConfig.setAttrValue(attrValueEntry.data(), 452 attrValueEntry.size(), false); 453 EXPECT_EQ(rc, PLDM_SUCCESS); 454 455 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 456 auto findEntry = 457 [&attrValueTable]( 458 uint16_t handle) -> 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