You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
7.7 KiB

  1. // Copyright 2022 Nick Brassel (@tzarc)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <numeric>
  4. #include "gtest/gtest.h"
  5. #include "gmock/gmock.h"
  6. #include "backing_mocks.hpp"
  7. class WearLeveling8Byte : public ::testing::Test {
  8. protected:
  9. void SetUp() override {
  10. MockBackingStore::Instance().reset_instance();
  11. wear_leveling_init();
  12. }
  13. };
  14. static std::array<std::uint8_t, WEAR_LEVELING_LOGICAL_SIZE> verify_data;
  15. static wear_leveling_status_t test_write(const uint32_t address, const void* value, size_t length) {
  16. memcpy(&verify_data[address], value, length);
  17. return wear_leveling_write(address, value, length);
  18. }
  19. /**
  20. * This test verifies that the first write after initialisation occurs after the FNV1a_64 hash location.
  21. */
  22. TEST_F(WearLeveling8Byte, FirstWriteOccursAfterHash) {
  23. auto& inst = MockBackingStore::Instance();
  24. uint8_t test_value = 0x15;
  25. test_write(0x02, &test_value, sizeof(test_value));
  26. EXPECT_EQ(inst.log_begin()->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid first write address.";
  27. }
  28. /**
  29. * This test verifies that the first write after initialisation occurs after the FNV1a_64 hash location, after an erase has occurred.
  30. */
  31. TEST_F(WearLeveling8Byte, FirstWriteOccursAfterHash_AfterErase) {
  32. auto& inst = MockBackingStore::Instance();
  33. uint8_t test_value = 0x15;
  34. wear_leveling_erase();
  35. test_write(0x02, &test_value, sizeof(test_value));
  36. EXPECT_EQ((inst.log_begin() + 1)->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid first write address.";
  37. }
  38. /**
  39. * This test ensures the correct number of backing store writes occurs with a multibyte write, given the input buffer size.
  40. */
  41. TEST_F(WearLeveling8Byte, MultibyteBackingStoreWriteCounts) {
  42. auto& inst = MockBackingStore::Instance();
  43. for (std::size_t length = 1; length <= 5; ++length) {
  44. // Clear things out
  45. std::fill(verify_data.begin(), verify_data.end(), 0);
  46. inst.reset_instance();
  47. wear_leveling_init();
  48. // Generate a test block of data
  49. std::vector<std::uint8_t> testvalue(length);
  50. std::iota(testvalue.begin(), testvalue.end(), 0x20);
  51. // Write the data
  52. EXPECT_EQ(test_write(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_SUCCESS) << "Write failed with incorrect status";
  53. // Check that we got the expected number of write log entries
  54. EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), 1);
  55. }
  56. }
  57. /**
  58. * This test forces consolidation by writing enough to the write log that it overflows, consolidating the data into the
  59. * base logical area.
  60. */
  61. TEST_F(WearLeveling8Byte, ConsolidationOverflow) {
  62. auto& inst = MockBackingStore::Instance();
  63. // Generate a test block of data
  64. std::array<std::uint8_t, WEAR_LEVELING_LOGICAL_SIZE> testvalue;
  65. // Write the data
  66. std::iota(testvalue.begin(), testvalue.end(), 0x20);
  67. EXPECT_EQ(test_write(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_CONSOLIDATED) << "Write returned incorrect status";
  68. uint8_t dummy = 0x40;
  69. EXPECT_EQ(test_write(0x04, &dummy, sizeof(dummy)), WEAR_LEVELING_SUCCESS) << "Write returned incorrect status";
  70. // Expected log:
  71. // [0]: multibyte, 5 bytes, backing address 0x18, logical address 0x00
  72. // [1]: multibyte, 5 bytes, backing address 0x20, logical address 0x05
  73. // [2]: multibyte, 5 bytes, backing address 0x28, logical address 0x0A, triggers consolidation
  74. // [3]: erase
  75. // [4]: consolidated data, backing address 0x00, logical address 0x00
  76. // [5]: consolidated data, backing address 0x08, logical address 0x08
  77. // [6]: FNV1a_64 result, backing address 0x10
  78. // [7]: multibyte, 1 byte, backing address 0x18, logical address 0x04
  79. EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), 8);
  80. // Verify the backing store writes for the write log
  81. std::size_t index;
  82. write_log_entry_t e;
  83. for (index = 0; index < 3; ++index) {
  84. auto write_iter = inst.log_begin() + index;
  85. EXPECT_EQ(write_iter->address, WEAR_LEVELING_LOGICAL_SIZE + 8 + (index * BACKING_STORE_WRITE_SIZE)) << "Invalid write log address";
  86. write_log_entry_t e;
  87. e.raw64 = write_iter->value;
  88. EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_MULTIBYTE) << "Invalid write log entry type";
  89. }
  90. // Verify the backing store erase
  91. {
  92. index = 3;
  93. auto write_iter = inst.log_begin() + index;
  94. e.raw64 = write_iter->value;
  95. EXPECT_TRUE(write_iter->erased) << "Backing store erase did not occur as required";
  96. }
  97. // Verify the backing store writes for consolidation
  98. for (index = 4; index < 6; ++index) {
  99. auto write_iter = inst.log_begin() + index;
  100. EXPECT_EQ(write_iter->address, (index - 4) * BACKING_STORE_WRITE_SIZE) << "Invalid write log entry address";
  101. }
  102. // Verify the FNV1a_64 write
  103. {
  104. EXPECT_EQ((inst.log_begin() + 6)->address, WEAR_LEVELING_LOGICAL_SIZE) << "Invalid write log address";
  105. e.raw64 = (inst.log_begin() + 6)->value;
  106. EXPECT_EQ(e.raw64, fnv_64a_buf(testvalue.data(), testvalue.size(), FNV1A_64_INIT)) << "Invalid checksum"; // Note that checksum is based on testvalue, as we overwrote one byte and need to consult the consolidated data, not the current
  107. }
  108. // Verify the final write
  109. EXPECT_EQ((inst.log_begin() + 7)->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid write log address";
  110. // Verify the data is what we expected
  111. std::array<std::uint8_t, WEAR_LEVELING_LOGICAL_SIZE> readback;
  112. EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data";
  113. EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback did not match";
  114. // Re-init and re-read, verifying the reload capability
  115. EXPECT_NE(wear_leveling_init(), WEAR_LEVELING_FAILED) << "Re-initialisation failed";
  116. EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data";
  117. EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback did not match";
  118. }
  119. /**
  120. * This test verifies multibyte readback gets canceled with an out-of-bounds address.
  121. */
  122. TEST_F(WearLeveling8Byte, PlaybackReadbackMultibyte_OOB) {
  123. auto& inst = MockBackingStore::Instance();
  124. auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t));
  125. // Invalid FNV1a_64 hash
  126. (logstart + 0)->set(0);
  127. // Set up a 2-byte logical write of [0x11,0x12] at logical offset 0x01
  128. auto entry0 = LOG_ENTRY_MAKE_MULTIBYTE(0x01, 2);
  129. entry0.raw8[3] = 0x11;
  130. entry0.raw8[4] = 0x12;
  131. (logstart + 1)->set(~entry0.raw64);
  132. // Set up a 2-byte logical write of [0x13,0x14] at logical offset 0x1000 (out of bounds)
  133. auto entry1 = LOG_ENTRY_MAKE_MULTIBYTE(0x1000, 2);
  134. entry1.raw8[3] = 0x13;
  135. entry1.raw8[4] = 0x14;
  136. (logstart + 2)->set(~entry1.raw64);
  137. // Set up a 2-byte logical write of [0x15,0x16] at logical offset 0x10
  138. auto entry2 = LOG_ENTRY_MAKE_MULTIBYTE(0x01, 2);
  139. entry2.raw8[3] = 0x15;
  140. entry2.raw8[4] = 0x16;
  141. (logstart + 3)->set(~entry2.raw64);
  142. EXPECT_EQ(inst.erasure_count(), 0) << "Invalid initial erase count";
  143. EXPECT_EQ(wear_leveling_init(), WEAR_LEVELING_CONSOLIDATED) << "Readback should have failed and triggered consolidation";
  144. EXPECT_EQ(inst.erasure_count(), 1) << "Invalid final erase count";
  145. uint8_t buf[2];
  146. wear_leveling_read(0x01, buf, sizeof(buf));
  147. EXPECT_EQ(buf[0], 0x11) << "Readback should have maintained the previous pre-failure value from the write log";
  148. EXPECT_EQ(buf[1], 0x12) << "Readback should have maintained the previous pre-failure value from the write log";
  149. }