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:
SetUpTestCase()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
findJsonEntry(const std::string & name)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
TearDownTestCase()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:
MockSystemConfig()80 MockSystemConfig() {}
81 MOCK_METHOD(void, ibmCompatibleAddedCallback, (sdbusplus::message_t&), ());
82 MOCK_METHOD(std::optional<std::filesystem::path>, getPlatformName, ());
83 };
84
TEST_F(TestBIOSConfig,buildTablesTest)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
TEST_F(TestBIOSConfig,setBIOSTable)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
TEST_F(TestBIOSConfig,getBIOSTableFailure)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
TEST_F(TestBIOSConfig,setAttrValueFailure)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
TEST_F(TestBIOSConfig,setAttrValue)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