blob: 6f886f04788568b1c8eb5aab4adfb4eff1a577df [file] [log] [blame]
Brandon Kimfcbc3db2022-06-06 21:26:18 -07001#include "buffer.hpp"
2#include "data_interface_mock.hpp"
3
Brandon Kim17ee1a92022-06-07 21:04:08 -07004#include <boost/endian/arithmetic.hpp>
5#include <boost/endian/conversion.hpp>
6
7#include <algorithm>
Brandon Kimfcbc3db2022-06-06 21:26:18 -07008#include <array>
9#include <cstdint>
10#include <memory>
11
12#include <gmock/gmock.h>
13#include <gtest/gtest.h>
14
15namespace bios_bmc_smm_error_logger
16{
17namespace
18{
19
20using ::testing::_;
21using ::testing::ElementsAreArray;
22using ::testing::InSequence;
23using ::testing::Return;
24
25class BufferTest : public ::testing::Test
26{
27 protected:
28 BufferTest() :
29 dataInterfaceMock(std::make_unique<DataInterfaceMock>()),
30 dataInterfaceMockPtr(dataInterfaceMock.get())
31 {
32 bufferImpl = std::make_unique<BufferImpl>(std::move(dataInterfaceMock));
33 testInitializationHeader.bmcInterfaceVersion = testBmcInterfaceVersion;
34 testInitializationHeader.queueSize = testQueueSize;
35 testInitializationHeader.ueRegionSize = testUeRegionSize;
Brandon Kim17ee1a92022-06-07 21:04:08 -070036 std::transform(testMagicNumber.begin(), testMagicNumber.end(),
37 testInitializationHeader.magicNumber.begin(),
38 [](uint32_t number) -> little_uint32_t {
39 return boost::endian::native_to_little(number);
40 });
Brandon Kimfcbc3db2022-06-06 21:26:18 -070041 }
42 ~BufferTest() override = default;
43
44 // CircularBufferHeader size is 0x30, ensure the test region is bigger
45 static constexpr size_t testRegionSize = 0x200;
46 static constexpr uint32_t testBmcInterfaceVersion = 123;
47 static constexpr uint16_t testQueueSize = 0x100;
48 static constexpr uint16_t testUeRegionSize = 0x50;
49 static constexpr std::array<uint32_t, 4> testMagicNumber = {
50 0x12345678, 0x22345678, 0x32345678, 0x42345678};
Brandon Kim17ee1a92022-06-07 21:04:08 -070051 static constexpr size_t bufferHeaderSize =
52 sizeof(struct CircularBufferHeader);
53
Brandon Kimfcbc3db2022-06-06 21:26:18 -070054 struct CircularBufferHeader testInitializationHeader
55 {};
56
57 std::unique_ptr<DataInterfaceMock> dataInterfaceMock;
58 DataInterfaceMock* dataInterfaceMockPtr;
Brandon Kimfcbc3db2022-06-06 21:26:18 -070059 std::unique_ptr<BufferImpl> bufferImpl;
60};
61
62TEST_F(BufferTest, BufferInitializeEraseFail)
63{
64 InSequence s;
Brandon Kim26660e92022-06-15 16:58:44 -070065 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
66 .WillOnce(Return(testRegionSize));
67 EXPECT_THROW(
68 try {
69 // Test too big of a proposed buffer compared to the memori size
70 uint16_t bigQueueSize = 0x181;
71 uint16_t bigUeRegionSize = 0x50;
72 bufferImpl->initialize(testBmcInterfaceVersion, bigQueueSize,
73 bigUeRegionSize, testMagicNumber);
74 } catch (const std::runtime_error& e) {
75 EXPECT_STREQ(
76 e.what(),
77 "[initialize] Proposed region size '513' "
78 "is bigger than the BMC's allocated MMIO region of '512'");
79 throw;
80 },
81 std::runtime_error);
82 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -070083
84 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
85 .WillOnce(Return(testRegionSize));
Brandon Kim26660e92022-06-15 16:58:44 -070086 size_t testProposedBufferSize =
87 sizeof(struct CircularBufferHeader) + testUeRegionSize + testQueueSize;
88 const std::vector<uint8_t> emptyArray(testProposedBufferSize, 0);
Brandon Kimfcbc3db2022-06-06 21:26:18 -070089 // Return a smaller write than the intended testRegionSize to test the error
90 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim26660e92022-06-15 16:58:44 -070091 .WillOnce(Return(testProposedBufferSize - 1));
Brandon Kimfcbc3db2022-06-06 21:26:18 -070092 EXPECT_THROW(
93 try {
94 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
95 testUeRegionSize, testMagicNumber);
96 } catch (const std::runtime_error& e) {
Brandon Kim26660e92022-06-15 16:58:44 -070097 EXPECT_STREQ(e.what(), "[initialize] Only erased '383'");
Brandon Kimfcbc3db2022-06-06 21:26:18 -070098 throw;
99 },
100 std::runtime_error);
Brandon Kim60cab572022-06-15 14:20:05 -0700101 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700102
103 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
104 .WillOnce(Return(testRegionSize));
105 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim26660e92022-06-15 16:58:44 -0700106 .WillOnce(Return(testProposedBufferSize));
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700107 // Return a smaller write than the intended initializationHeader to test the
108 // error
109 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _)).WillOnce(Return(0));
110 EXPECT_THROW(
111 try {
112 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
113 testUeRegionSize, testMagicNumber);
114 } catch (const std::runtime_error& e) {
Brandon Kim26660e92022-06-15 16:58:44 -0700115 EXPECT_STREQ(e.what(),
116 "[initialize] Only wrote '0' bytes of the header");
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700117 throw;
118 },
119 std::runtime_error);
Brandon Kim60cab572022-06-15 14:20:05 -0700120 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700121}
122
123TEST_F(BufferTest, BufferInitializePass)
124{
125 InSequence s;
126 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
127 .WillOnce(Return(testRegionSize));
Brandon Kim26660e92022-06-15 16:58:44 -0700128 size_t testProposedBufferSize =
129 sizeof(struct CircularBufferHeader) + testUeRegionSize + testQueueSize;
130 const std::vector<uint8_t> emptyArray(testProposedBufferSize, 0);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700131 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim26660e92022-06-15 16:58:44 -0700132 .WillOnce(Return(testProposedBufferSize));
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700133
134 uint8_t* testInitializationHeaderPtr =
135 reinterpret_cast<uint8_t*>(&testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700136 EXPECT_CALL(*dataInterfaceMockPtr,
137 write(0, ElementsAreArray(testInitializationHeaderPtr,
Brandon Kim17ee1a92022-06-07 21:04:08 -0700138 bufferHeaderSize)))
139 .WillOnce(Return(bufferHeaderSize));
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700140 EXPECT_NO_THROW(bufferImpl->initialize(testBmcInterfaceVersion,
141 testQueueSize, testUeRegionSize,
142 testMagicNumber));
Brandon Kim60cab572022-06-15 14:20:05 -0700143 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700144}
145
Brandon Kim17ee1a92022-06-07 21:04:08 -0700146TEST_F(BufferTest, BufferHeaderReadFail)
147{
148 std::vector<std::uint8_t> testBytesRead{};
149 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
150 .WillOnce(Return(testBytesRead));
151 EXPECT_THROW(
152 try {
153 bufferImpl->readBufferHeader();
154 } catch (const std::runtime_error& e) {
155 EXPECT_STREQ(e.what(),
156 "Buffer header read only read '0', expected '48'");
157 throw;
158 },
159 std::runtime_error);
160}
161
162TEST_F(BufferTest, BufferHeaderReadPass)
163{
164 uint8_t* testInitializationHeaderPtr =
165 reinterpret_cast<uint8_t*>(&testInitializationHeader);
166 std::vector<uint8_t> testInitializationHeaderVector(
167 testInitializationHeaderPtr,
168 testInitializationHeaderPtr + bufferHeaderSize);
169
170 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
171 .WillOnce(Return(testInitializationHeaderVector));
172 EXPECT_NO_THROW(bufferImpl->readBufferHeader());
173 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
174}
175
Brandon Kimcf0b9752022-06-15 10:32:21 -0700176TEST_F(BufferTest, BufferUpdateReadPtrFail)
177{
178 // Return write size that is not 2 which is sizeof(little_uint16_t)
179 constexpr size_t wrongWriteSize = 1;
180 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
181 .WillOnce(Return(wrongWriteSize));
182 EXPECT_THROW(
183 try {
184 bufferImpl->updateReadPtr(0);
185 } catch (const std::runtime_error& e) {
186 EXPECT_STREQ(
187 e.what(),
188 "[updateReadPtr] Wrote '1' bytes, instead of expected '2'");
189 throw;
190 },
191 std::runtime_error);
192}
193
194TEST_F(BufferTest, BufferUpdateReadPtrPass)
195{
196 constexpr size_t expectedWriteSize = 2;
197 constexpr uint8_t expectedBmcReadPtrOffset = 0x20;
198 // Check that we truncate the highest 16bits
199 const uint32_t testNewReadPtr = 0x99881234;
200 const std::vector<uint8_t> expectedReadPtr{0x34, 0x12};
201
202 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
203 ElementsAreArray(expectedReadPtr)))
204 .WillOnce(Return(expectedWriteSize));
205 EXPECT_NO_THROW(bufferImpl->updateReadPtr(testNewReadPtr));
206}
207
Brandon Kim9836cfa2022-06-15 11:21:11 -0700208class BufferWraparoundReadTest : public BufferTest
209{
210 protected:
211 BufferWraparoundReadTest()
212 {
213 // Initialize the memory and the cachedBufferHeader
214 InSequence s;
215 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
216 .WillOnce(Return(testRegionSize));
Brandon Kim26660e92022-06-15 16:58:44 -0700217 size_t testProposedBufferSize = sizeof(struct CircularBufferHeader) +
218 testUeRegionSize + testQueueSize;
219 const std::vector<uint8_t> emptyArray(testProposedBufferSize, 0);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700220 EXPECT_CALL(*dataInterfaceMockPtr,
221 write(0, ElementsAreArray(emptyArray)))
Brandon Kim26660e92022-06-15 16:58:44 -0700222 .WillOnce(Return(testProposedBufferSize));
Brandon Kim9836cfa2022-06-15 11:21:11 -0700223
224 uint8_t* testInitializationHeaderPtr =
225 reinterpret_cast<uint8_t*>(&testInitializationHeader);
226 EXPECT_CALL(*dataInterfaceMockPtr,
227 write(0, ElementsAreArray(testInitializationHeaderPtr,
228 bufferHeaderSize)))
229 .WillOnce(Return(bufferHeaderSize));
230 EXPECT_NO_THROW(bufferImpl->initialize(testBmcInterfaceVersion,
231 testQueueSize, testUeRegionSize,
232 testMagicNumber));
233 }
234 static constexpr size_t expectedWriteSize = 2;
235 static constexpr uint8_t expectedBmcReadPtrOffset = 0x20;
236 static constexpr size_t expectedqueueOffset = 0x30 + testUeRegionSize;
237};
238
Brandon Kim35d43352022-06-16 11:13:36 -0700239TEST_F(BufferWraparoundReadTest, ParamsTooBigFail)
Brandon Kim9836cfa2022-06-15 11:21:11 -0700240{
241 InSequence s;
Brandon Kim35d43352022-06-16 11:13:36 -0700242
243 size_t tooBigOffset = testQueueSize + 1;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700244 EXPECT_THROW(
245 try {
Brandon Kim35d43352022-06-16 11:13:36 -0700246 bufferImpl->wraparoundRead(tooBigOffset, /* length */ 1);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700247 } catch (const std::runtime_error& e) {
Brandon Kim26660e92022-06-15 16:58:44 -0700248 EXPECT_STREQ(
249 e.what(),
Brandon Kim35d43352022-06-16 11:13:36 -0700250 "[wraparoundRead] relativeOffset '257' was bigger than queueSize '256'");
251 throw;
252 },
253 std::runtime_error);
254
255 size_t tooBigLength = testQueueSize + 1;
256 EXPECT_THROW(
257 try {
258 bufferImpl->wraparoundRead(/* relativeOffset */ 0, tooBigLength);
259 } catch (const std::runtime_error& e) {
260 EXPECT_STREQ(e.what(), "[wraparoundRead] length '257' was bigger "
261 "than queueSize '256'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700262 throw;
263 },
264 std::runtime_error);
265}
266
Brandon Kim35d43352022-06-16 11:13:36 -0700267TEST_F(BufferWraparoundReadTest, NoWrapAroundReadFails)
Brandon Kim9836cfa2022-06-15 11:21:11 -0700268{
269 InSequence s;
Brandon Kim35d43352022-06-16 11:13:36 -0700270 size_t testLength = 0x10;
271 size_t testOffset = 0x20;
272
273 // Fail the first read
274 std::vector<std::uint8_t> shortTestBytesRead(testLength - 1);
275 EXPECT_CALL(*dataInterfaceMockPtr,
276 read(testOffset + expectedqueueOffset, testLength))
277 .WillOnce(Return(shortTestBytesRead));
278
Brandon Kim9836cfa2022-06-15 11:21:11 -0700279 EXPECT_THROW(
280 try {
Brandon Kim35d43352022-06-16 11:13:36 -0700281 bufferImpl->wraparoundRead(testOffset, testLength);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700282 } catch (const std::runtime_error& e) {
Brandon Kim35d43352022-06-16 11:13:36 -0700283 EXPECT_STREQ(e.what(),
284 "[wraparoundRead] Read '15' which was not the "
285 "requested length of '16'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700286 throw;
287 },
288 std::runtime_error);
289}
290
291TEST_F(BufferWraparoundReadTest, NoWrapAroundReadPass)
292{
293 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700294 size_t testLength = 0x10;
Brandon Kim35d43352022-06-16 11:13:36 -0700295 size_t testOffset = 0x20;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700296
297 // Successfully read all the requested length without a wrap around
298 std::vector<std::uint8_t> testBytesRead(testLength);
Brandon Kim35d43352022-06-16 11:13:36 -0700299 EXPECT_CALL(*dataInterfaceMockPtr,
300 read(testOffset + expectedqueueOffset, testLength))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700301 .WillOnce(Return(testBytesRead));
302
303 // Call to updateReadPtr is triggered
304 const std::vector<uint8_t> expectedReadPtr{
305 static_cast<uint8_t>(testOffset + testLength), 0x0};
306 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
307 ElementsAreArray(expectedReadPtr)))
308 .WillOnce(Return(expectedWriteSize));
309
310 EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
311 ElementsAreArray(testBytesRead));
Brandon Kim35d43352022-06-16 11:13:36 -0700312 struct CircularBufferHeader cachedBufferHeader =
313 bufferImpl->getCachedBufferHeader();
314 // The bmcReadPtr should have been updated
315 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
316 testOffset + testLength);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700317}
318
319TEST_F(BufferWraparoundReadTest, WrapAroundReadFails)
320{
321 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700322 size_t testBytesLeft = 3;
323 size_t testLength = 0x10;
Brandon Kim26660e92022-06-15 16:58:44 -0700324 size_t testOffset = testQueueSize - (testLength - testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700325
Brandon Kim35d43352022-06-16 11:13:36 -0700326 // Read until the end of the queue
Brandon Kim9836cfa2022-06-15 11:21:11 -0700327 std::vector<std::uint8_t> testBytesReadShort(testLength - testBytesLeft);
Brandon Kim35d43352022-06-16 11:13:36 -0700328 EXPECT_CALL(*dataInterfaceMockPtr, read(testOffset + expectedqueueOffset,
329 testLength - testBytesLeft))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700330 .WillOnce(Return(testBytesReadShort));
331
332 // Read 1 byte short after wraparound
333 std::vector<std::uint8_t> testBytesLeftReadShort(testBytesLeft - 1);
334 EXPECT_CALL(*dataInterfaceMockPtr, read(expectedqueueOffset, testBytesLeft))
335 .WillOnce(Return(testBytesLeftReadShort));
336
337 EXPECT_THROW(
338 try {
339 bufferImpl->wraparoundRead(testOffset, testLength);
340 } catch (const std::runtime_error& e) {
Brandon Kim35d43352022-06-16 11:13:36 -0700341 EXPECT_STREQ(
342 e.what(),
343 "[wraparoundRead] Buffer wrapped around but read '2' which was "
344 "not the requested lenght of '3'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700345 throw;
346 },
347 std::runtime_error);
348}
349
350TEST_F(BufferWraparoundReadTest, WrapAroundReadPasses)
351{
352 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700353 size_t testBytesLeft = 3;
354 size_t testLength = 0x10;
Brandon Kim26660e92022-06-15 16:58:44 -0700355 size_t testOffset = testQueueSize - (testLength - testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700356
Brandon Kim35d43352022-06-16 11:13:36 -0700357 // Read to the end of the queue
Brandon Kim9836cfa2022-06-15 11:21:11 -0700358 std::vector<std::uint8_t> testBytesReadFirst{16, 15, 14, 13, 12, 11, 10,
359 9, 8, 7, 6, 5, 4};
Brandon Kim35d43352022-06-16 11:13:36 -0700360 EXPECT_CALL(*dataInterfaceMockPtr, read(testOffset + expectedqueueOffset,
361 testLength - testBytesLeft))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700362 .WillOnce(Return(testBytesReadFirst));
363
364 std::vector<std::uint8_t> testBytesReadSecond{3, 2, 1};
365 EXPECT_CALL(*dataInterfaceMockPtr, read(expectedqueueOffset, testBytesLeft))
366 .WillOnce(Return(testBytesReadSecond));
367
368 // Call to updateReadPtr is triggered
369 const std::vector<uint8_t> expectedReadPtr{
Brandon Kim26660e92022-06-15 16:58:44 -0700370 static_cast<uint8_t>(testBytesLeft), 0x0};
Brandon Kim9836cfa2022-06-15 11:21:11 -0700371 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
372 ElementsAreArray(expectedReadPtr)))
373 .WillOnce(Return(expectedWriteSize));
374
375 std::vector<std::uint8_t> expectedBytes = {16, 15, 14, 13, 12, 11, 10, 9,
376 8, 7, 6, 5, 4, 3, 2, 1};
377 EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
378 ElementsAreArray(expectedBytes));
Brandon Kim35d43352022-06-16 11:13:36 -0700379 struct CircularBufferHeader cachedBufferHeader =
380 bufferImpl->getCachedBufferHeader();
381 // The bmcReadPtr should have been updated to reflect the wraparound
382 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
383 testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700384}
385
Brandon Kim40ce08e2022-06-15 16:58:44 -0700386class BufferEntryTest : public BufferWraparoundReadTest
Brandon Kim7bac2d62022-06-07 21:37:51 -0700387{
388 protected:
Brandon Kim40ce08e2022-06-15 16:58:44 -0700389 BufferEntryTest()
Brandon Kim7bac2d62022-06-07 21:37:51 -0700390 {
391 testEntryHeader.sequenceId = testSequenceId;
392 testEntryHeader.entrySize = testEntrySize;
393 testEntryHeader.checksum = testChecksum;
394 testEntryHeader.rdeCommandType = testRdeCommandType;
395 }
Brandon Kim40ce08e2022-06-15 16:58:44 -0700396 ~BufferEntryTest() override = default;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700397
Brandon Kim35d43352022-06-16 11:13:36 -0700398 void wraparoundReadMock(const uint32_t relativeOffset,
399 std::span<std::uint8_t> expetedBytesOutput)
Brandon Kim7bac2d62022-06-07 21:37:51 -0700400 {
Brandon Kim35d43352022-06-16 11:13:36 -0700401 InSequence s;
402 const uint32_t queueSizeToQueueEnd = testQueueSize - relativeOffset;
403
404 // This will wrap, split the read mocks in 2
405 if (expetedBytesOutput.size() > queueSizeToQueueEnd)
406 {
407 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
408 .WillOnce(Return(std::vector<std::uint8_t>(
409 expetedBytesOutput.begin(),
410 expetedBytesOutput.begin() + queueSizeToQueueEnd)));
411 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
412 .WillOnce(Return(std::vector<std::uint8_t>(
413 expetedBytesOutput.begin() + queueSizeToQueueEnd,
414 expetedBytesOutput.end())));
415 }
416 else
417 {
418 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
419 .WillOnce(Return(std::vector<std::uint8_t>(
420 expetedBytesOutput.begin(), expetedBytesOutput.end())));
421 }
Brandon Kim7bac2d62022-06-07 21:37:51 -0700422
423 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
424 .WillOnce(Return(expectedWriteSize));
425 }
426
427 static constexpr size_t entryHeaderSize = sizeof(struct QueueEntryHeader);
428 static constexpr uint16_t testSequenceId = 0;
429 static constexpr uint16_t testEntrySize = 0x20;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700430 static constexpr uint8_t testRdeCommandType = 0x01;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700431 // Calculated checksum for the header
432 static constexpr uint8_t testChecksum =
433 (testSequenceId ^ testEntrySize ^ testRdeCommandType);
Brandon Kim35d43352022-06-16 11:13:36 -0700434 size_t testOffset = 0x20;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700435
436 struct QueueEntryHeader testEntryHeader
437 {};
438};
439
Brandon Kim40ce08e2022-06-15 16:58:44 -0700440TEST_F(BufferEntryTest, ReadEntryHeaderPass)
Brandon Kim7bac2d62022-06-07 21:37:51 -0700441{
442 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
443 std::vector<uint8_t> testEntryHeaderVector(
444 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim35d43352022-06-16 11:13:36 -0700445 wraparoundReadMock(testOffset, testEntryHeaderVector);
Brandon Kim7bac2d62022-06-07 21:37:51 -0700446 EXPECT_EQ(bufferImpl->readEntryHeader(testOffset), testEntryHeader);
Brandon Kim35d43352022-06-16 11:13:36 -0700447 // Check the bmcReadPtr
448 struct CircularBufferHeader cachedBufferHeader =
449 bufferImpl->getCachedBufferHeader();
450 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
451 testOffset + testEntryHeaderVector.size());
Brandon Kim7bac2d62022-06-07 21:37:51 -0700452}
453
Brandon Kim40ce08e2022-06-15 16:58:44 -0700454TEST_F(BufferEntryTest, ReadEntryChecksumFail)
455{
456 InSequence s;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700457 std::vector<uint8_t> testEntryVector(testEntrySize);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700458 // Offset the checksum by 1
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700459 testEntryHeader.checksum += 1;
Brandon Kim40ce08e2022-06-15 16:58:44 -0700460 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
461 std::vector<uint8_t> testEntryHeaderVector(
462 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim35d43352022-06-16 11:13:36 -0700463 wraparoundReadMock(testOffset, testEntryHeaderVector);
464 wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700465 EXPECT_THROW(
466 try {
467 bufferImpl->readEntry(testOffset);
468 } catch (const std::runtime_error& e) {
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700469 // Calculation: testChecksum (0x21) XOR (0x22) = 3
Brandon Kim40ce08e2022-06-15 16:58:44 -0700470 EXPECT_STREQ(e.what(),
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700471 "[readEntry] Checksum was '3', expected '0'");
Brandon Kim40ce08e2022-06-15 16:58:44 -0700472 throw;
473 },
474 std::runtime_error);
475}
476
477TEST_F(BufferEntryTest, ReadEntryPass)
478{
479 InSequence s;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700480 // We expect this will bump checksum up by "testEntrySize" = 0xff ^ 0xff ...
481 // (20 times) = 0 therefore leave the checksum as is
Brandon Kim35d43352022-06-16 11:13:36 -0700482 std::vector<uint8_t> testEntryVector(testEntrySize, 0xff);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700483 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
484 std::vector<uint8_t> testEntryHeaderVector(
485 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim35d43352022-06-16 11:13:36 -0700486 // Set testOffset so that we can test the wraparound here as well on our
487 // second read for the entry (by 1 byte)
488 testOffset = testQueueSize - entryHeaderSize - 1;
489 wraparoundReadMock(testOffset, testEntryHeaderVector);
490 wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700491
492 EntryPair testedEntryPair;
493 EXPECT_NO_THROW(testedEntryPair = bufferImpl->readEntry(testOffset));
494 EXPECT_EQ(testedEntryPair.first, testEntryHeader);
495 EXPECT_THAT(testedEntryPair.second, ElementsAreArray(testEntryVector));
Brandon Kim35d43352022-06-16 11:13:36 -0700496 struct CircularBufferHeader cachedBufferHeader =
497 bufferImpl->getCachedBufferHeader();
498 // The bmcReadPtr should have been updated to reflect the wraparound
499 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
500 testEntrySize - 1);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700501}
502
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700503} // namespace
504} // namespace bios_bmc_smm_error_logger