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