blob: 9b7fe8a0b882266550763f00ef8fa0587f78cad8 [file] [log] [blame]
Archana Kakani46f352e2024-03-17 08:21:08 -05001#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
17using namespace pldm::bios::utils;
18using namespace pldm::responder::bios;
19using namespace pldm::utils;
20
21using ::testing::_;
22using ::testing::ElementsAreArray;
23using ::testing::Return;
24using ::testing::StrEq;
25using ::testing::Throw;
26
27class TestSystemSpecificBIOSConfig : public ::testing::Test
28{
29 public:
Manojkiran Eda2576aec2024-06-17 12:05:17 +053030 static void SetUpTestCase() // will execute once at the beginning of all
Archana Kakani46f352e2024-03-17 08:21:08 -050031 // 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
78fs::path TestSystemSpecificBIOSConfig::tableDir;
79std::vector<Json> TestSystemSpecificBIOSConfig::jsons;
80
81class 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
89TEST_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
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400108 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"};
Archana Kakani46f352e2024-03-17 08:21:08 -0500128 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>());
Archana Kakani46f352e2024-03-17 08:21:08 -0500164 EXPECT_EQ(stringField.defString,
165 jsonEntry->at("default_string").get<std::string>());
Archana Kakani7d475702024-05-22 08:30:27 -0500166 EXPECT_EQ(stringField.defLength,
167 (stringField.defString).length());
Archana Kakani46f352e2024-03-17 08:21:08 -0500168 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);
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400217 auto attrEntry =
218 table::attribute::findByHandle(*attrTable, header.attrHandle);
Archana Kakani46f352e2024-03-17 08:21:08 -0500219 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
262TEST_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
333TEST_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
359TEST_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
377TEST_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 */
Manojkiran Eda2576aec2024-06-17 12:05:17 +0530390 'a', 'b', 'c', 'd', /* default value string handle index */
Archana Kakani46f352e2024-03-17 08:21:08 -0500391 };
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);
Manojkiran Eda2576aec2024-06-17 12:05:17 +0530399 std::cout << "Error in setting Attribute " << rc << std::endl;
Archana Kakani46f352e2024-03-17 08:21:08 -0500400 EXPECT_EQ(rc, PLDM_BIOS_TABLE_UNAVAILABLE);
401}
402
403TEST_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 */
Manojkiran Eda2576aec2024-06-17 12:05:17 +0530440 'a', 'b', 'c', 'd', /* default value string handle index */
Archana Kakani46f352e2024-03-17 08:21:08 -0500441 };
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);
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400457 auto findEntry = [&attrValueTable](uint16_t handle)
458 -> const pldm_bios_attr_val_table_entry* {
Archana Kakani46f352e2024-03-17 08:21:08 -0500459 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}