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