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 TestBIOSConfig : public ::testing::Test 28 { 29 public: 30 static void SetUpTestCase() // will execute once at the begining of all 31 // TestBIOSConfig 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 // TestBIOSConfig 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 TestBIOSConfig::tableDir; 79 std::vector<Json> TestBIOSConfig::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(TestBIOSConfig, buildTablesTest) 90 { 91 MockdBusHandler dbusHandler; 92 MockSystemConfig mockSystemConfig; 93 std::string biosFilePath("./bios_jsons"); 94 95 BIOSConfig biosConfig(biosFilePath.c_str(), tableDir.c_str(), &dbusHandler, 96 0, 0, nullptr, nullptr, &mockSystemConfig, []() {}); 97 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 98 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 99 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 100 101 EXPECT_TRUE(stringTable); 102 EXPECT_TRUE(attrTable); 103 EXPECT_TRUE(attrValueTable); 104 105 std::set<std::string> expectedStrings = {"HMCManagedState", 106 "On", 107 "Off", 108 "FWBootSide", 109 "Perm", 110 "Temp", 111 "InbandCodeUpdate", 112 "Allowed", 113 "Allowed", 114 "NotAllowed", 115 "CodeUpdatePolicy", 116 "Concurrent", 117 "Disruptive", 118 "VDD_AVSBUS_RAIL", 119 "SBE_IMAGE_MINIMUM_VALID_ECS", 120 "INTEGER_INVALID_CASE", 121 "str_example1", 122 "str_example2", 123 "str_example3"}; 124 std::set<std::string> strings; 125 for (auto entry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>( 126 stringTable->data(), stringTable->size())) 127 { 128 auto str = table::string::decodeString(entry); 129 strings.emplace(str); 130 } 131 132 EXPECT_EQ(strings, expectedStrings); 133 134 BIOSStringTable biosStringTable(*stringTable); 135 136 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 137 attrTable->size())) 138 { 139 auto header = table::attribute::decodeHeader(entry); 140 auto attrName = biosStringTable.findString(header.stringHandle); 141 auto jsonEntry = findJsonEntry(attrName); 142 EXPECT_TRUE(jsonEntry); 143 switch (header.attrType) 144 { 145 case PLDM_BIOS_STRING: 146 case PLDM_BIOS_STRING_READ_ONLY: 147 { 148 auto stringField = table::attribute::decodeStringEntry(entry); 149 auto stringType = BIOSStringAttribute::strTypeMap.at( 150 jsonEntry->at("string_type").get<std::string>()); 151 EXPECT_EQ(stringField.stringType, 152 static_cast<uint8_t>(stringType)); 153 154 EXPECT_EQ( 155 stringField.minLength, 156 jsonEntry->at("minimum_string_length").get<uint16_t>()); 157 EXPECT_EQ( 158 stringField.maxLength, 159 jsonEntry->at("maximum_string_length").get<uint16_t>()); 160 EXPECT_EQ( 161 stringField.defLength, 162 jsonEntry->at("default_string_length").get<uint16_t>()); 163 EXPECT_EQ(stringField.defString, 164 jsonEntry->at("default_string").get<std::string>()); 165 break; 166 } 167 case PLDM_BIOS_INTEGER: 168 case PLDM_BIOS_INTEGER_READ_ONLY: 169 { 170 auto integerField = table::attribute::decodeIntegerEntry(entry); 171 EXPECT_EQ(integerField.lowerBound, 172 jsonEntry->at("lower_bound").get<uint64_t>()); 173 EXPECT_EQ(integerField.upperBound, 174 jsonEntry->at("upper_bound").get<uint64_t>()); 175 EXPECT_EQ(integerField.scalarIncrement, 176 jsonEntry->at("scalar_increment").get<uint32_t>()); 177 EXPECT_EQ(integerField.defaultValue, 178 jsonEntry->at("default_value").get<uint64_t>()); 179 break; 180 } 181 case PLDM_BIOS_ENUMERATION: 182 case PLDM_BIOS_ENUMERATION_READ_ONLY: 183 { 184 auto [pvHdls, 185 defInds] = table::attribute::decodeEnumEntry(entry); 186 auto possibleValues = jsonEntry->at("possible_values") 187 .get<std::vector<std::string>>(); 188 std::vector<std::string> strings; 189 for (auto pv : pvHdls) 190 { 191 auto s = biosStringTable.findString(pv); 192 strings.emplace_back(s); 193 } 194 EXPECT_EQ(strings, possibleValues); 195 EXPECT_EQ(defInds.size(), 1); 196 197 auto defValue = biosStringTable.findString(pvHdls[defInds[0]]); 198 auto defaultValues = jsonEntry->at("default_values") 199 .get<std::vector<std::string>>(); 200 EXPECT_EQ(defValue, defaultValues[0]); 201 202 break; 203 } 204 default: 205 EXPECT_TRUE(false); 206 break; 207 } 208 } 209 210 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>( 211 attrValueTable->data(), attrValueTable->size())) 212 { 213 auto header = table::attribute_value::decodeHeader(entry); 214 auto attrEntry = table::attribute::findByHandle(*attrTable, 215 header.attrHandle); 216 auto attrHeader = table::attribute::decodeHeader(attrEntry); 217 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 218 auto jsonEntry = findJsonEntry(attrName); 219 EXPECT_TRUE(jsonEntry); 220 switch (header.attrType) 221 { 222 case PLDM_BIOS_STRING: 223 case PLDM_BIOS_STRING_READ_ONLY: 224 { 225 auto value = table::attribute_value::decodeStringEntry(entry); 226 auto defValue = 227 jsonEntry->at("default_string").get<std::string>(); 228 EXPECT_EQ(value, defValue); 229 break; 230 } 231 case PLDM_BIOS_INTEGER: 232 case PLDM_BIOS_INTEGER_READ_ONLY: 233 { 234 auto value = table::attribute_value::decodeIntegerEntry(entry); 235 auto defValue = jsonEntry->at("default_value").get<uint64_t>(); 236 EXPECT_EQ(value, defValue); 237 break; 238 } 239 case PLDM_BIOS_ENUMERATION: 240 case PLDM_BIOS_ENUMERATION_READ_ONLY: 241 { 242 auto indices = table::attribute_value::decodeEnumEntry(entry); 243 EXPECT_EQ(indices.size(), 1); 244 auto possibleValues = jsonEntry->at("possible_values") 245 .get<std::vector<std::string>>(); 246 247 auto defValues = jsonEntry->at("default_values") 248 .get<std::vector<std::string>>(); 249 EXPECT_EQ(possibleValues[indices[0]], defValues[0]); 250 break; 251 } 252 default: 253 EXPECT_TRUE(false); 254 break; 255 } 256 } 257 } 258 259 TEST_F(TestBIOSConfig, setBIOSTable) 260 { 261 MockdBusHandler dbusHandler; 262 MockSystemConfig mockSystemConfig; 263 264 BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr, 265 nullptr, &mockSystemConfig, []() {}); 266 267 std::set<std::string> strings{"pvm_system_name", "pvm_stop_at_standby", 268 "fw_boot_side", "fw_next_boot_side"}; 269 270 Table table; 271 for (const auto& elem : strings) 272 { 273 table::string::constructEntry(table, elem); 274 } 275 276 table::appendPadAndChecksum(table); 277 auto rc = biosConfig.setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 278 EXPECT_EQ(rc, PLDM_SUCCESS); 279 280 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 281 EXPECT_TRUE(stringTable); 282 } 283 284 TEST_F(TestBIOSConfig, getBIOSTableFailure) 285 { 286 MockdBusHandler dbusHandler; 287 MockSystemConfig mockSystemConfig; 288 289 BIOSConfig biosConfig("./jsons", tableDir.c_str(), &dbusHandler, 0, 0, 290 nullptr, nullptr, &mockSystemConfig, []() {}); 291 292 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 293 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 294 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 295 296 EXPECT_FALSE(stringTable); 297 EXPECT_FALSE(attrTable); 298 EXPECT_FALSE(attrValueTable); 299 } 300 301 TEST_F(TestBIOSConfig, setAttrValueFailure) 302 { 303 MockdBusHandler dbusHandler; 304 MockSystemConfig mockSystemConfig; 305 306 BIOSConfig biosConfig("./jsons", tableDir.c_str(), &dbusHandler, 0, 0, 307 nullptr, nullptr, &mockSystemConfig, []() {}); 308 309 std::vector<uint8_t> attrValueEntry{ 310 0, 0, /* attr handle */ 311 1, /* attr type string read-write */ 312 4, 0, /* current string length */ 313 'a', 'b', 'c', 'd', /* defaut value string handle index */ 314 }; 315 316 uint16_t attrHandle{10}; 317 attrValueEntry[0] = attrHandle & 0xff; 318 attrValueEntry[1] = (attrHandle >> 8) & 0xff; 319 320 auto rc = biosConfig.setAttrValue(attrValueEntry.data(), 321 attrValueEntry.size(), false); 322 EXPECT_EQ(rc, PLDM_BIOS_TABLE_UNAVAILABLE); 323 } 324 325 TEST_F(TestBIOSConfig, setAttrValue) 326 { 327 MockdBusHandler dbusHandler; 328 MockSystemConfig mockSystemConfig; 329 330 BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0, 331 nullptr, nullptr, &mockSystemConfig, []() {}); 332 333 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 334 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 335 336 BIOSStringTable biosStringTable(*stringTable); 337 BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(attrTable->data(), 338 attrTable->size()); 339 auto stringHandle = biosStringTable.findHandle("str_example1"); 340 uint16_t attrHandle{}; 341 342 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 343 attrTable->size())) 344 { 345 auto header = table::attribute::decodeHeader(entry); 346 if (header.stringHandle == stringHandle) 347 { 348 attrHandle = header.attrHandle; 349 break; 350 } 351 } 352 353 EXPECT_NE(attrHandle, 0); 354 355 std::vector<uint8_t> attrValueEntry{ 356 0, 0, /* attr handle */ 357 1, /* attr type string read-write */ 358 4, 0, /* current string length */ 359 'a', 'b', 'c', 'd', /* defaut value string handle index */ 360 }; 361 362 attrValueEntry[0] = attrHandle & 0xff; 363 attrValueEntry[1] = (attrHandle >> 8) & 0xff; 364 365 DBusMapping dbusMapping{"/xyz/abc/def", 366 "xyz.openbmc_project.str_example1.value", 367 "Str_example1", "string"}; 368 PropertyValue value = std::string("abcd"); 369 EXPECT_CALL(dbusHandler, setDbusProperty(dbusMapping, value)).Times(1); 370 371 auto rc = biosConfig.setAttrValue(attrValueEntry.data(), 372 attrValueEntry.size(), false); 373 EXPECT_EQ(rc, PLDM_SUCCESS); 374 375 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 376 auto findEntry = 377 [&attrValueTable]( 378 uint16_t handle) -> const pldm_bios_attr_val_table_entry* { 379 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>( 380 attrValueTable->data(), attrValueTable->size())) 381 { 382 auto [attrHandle, _] = table::attribute_value::decodeHeader(entry); 383 if (attrHandle == handle) 384 return entry; 385 } 386 return nullptr; 387 }; 388 389 auto entry = findEntry(attrHandle); 390 EXPECT_NE(entry, nullptr); 391 392 auto p = reinterpret_cast<const uint8_t*>(entry); 393 EXPECT_THAT(std::vector<uint8_t>(p, p + attrValueEntry.size()), 394 ElementsAreArray(attrValueEntry)); 395 } 396