summaryrefslogtreecommitdiffstats
path: root/quantum/wear_leveling/tests/backing_mocks.cpp
blob: 1dbb26f8e7dd727d62bb6162cb9cbfbb27fe41e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2022 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "backing_mocks.hpp"

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Backing Store Mock implementation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MockBackingStore::reset_instance() {
    for (auto&& e : backing_storage)
        e.reset();

    locked = true;

    backing_erasure_count     = 0;
    backing_max_write_count   = 0;
    backing_total_write_count = 0;

    backing_init_invoke_count   = 0;
    backing_unlock_invoke_count = 0;
    backing_erase_invoke_count  = 0;
    backing_write_invoke_count  = 0;
    backing_lock_invoke_count   = 0;

    init_success_callback   = [](std::uint64_t) { return true; };
    erase_success_callback  = [](std::uint64_t) { return true; };
    unlock_success_callback = [](std::uint64_t) { return true; };
    write_success_callback  = [](std::uint64_t, std::uint32_t) { return true; };
    lock_success_callback   = [](std::uint64_t) { return true; };

    write_log.clear();
}

bool MockBackingStore::init(void) {
    ++backing_init_invoke_count;

    if (init_success_callback) {
        return init_success_callback(backing_init_invoke_count);
    }
    return true;
}

bool MockBackingStore::unlock(void) {
    ++backing_unlock_invoke_count;

    EXPECT_TRUE(is_locked()) << "Attempted to unlock but was not locked";
    locked = false;

    if (unlock_success_callback) {
        return unlock_success_callback(backing_unlock_invoke_count);
    }
    return true;
}

bool MockBackingStore::erase(void) {
    ++backing_erase_invoke_count;

    // Erase each slot
    for (std::size_t i = 0; i < backing_storage.size(); ++i) {
        // Drop out of erase early with failure if we need to
        if (erase_success_callback && !erase_success_callback(backing_erase_invoke_count)) {
            append_log(true);
            return false;
        }

        backing_storage[i].erase();
    }

    // Keep track of the erase in the write log so that we can verify during tests
    append_log(true);

    ++backing_erasure_count;
    return true;
}

bool MockBackingStore::write(uint32_t address, backing_store_int_t value) {
    ++backing_write_invoke_count;

    // precondition: value's buffer size already matches BACKING_STORE_WRITE_SIZE
    EXPECT_TRUE(address % BACKING_STORE_WRITE_SIZE == 0) << "Supplied address was not aligned with the backing store integral size";
    EXPECT_TRUE(address + BACKING_STORE_WRITE_SIZE <= WEAR_LEVELING_BACKING_SIZE) << "Address would result of out-of-bounds access";
    EXPECT_FALSE(is_locked()) << "Write was attempted without being unlocked first";

    // Drop out of write early with failure if we need to
    if (write_success_callback && !write_success_callback(backing_write_invoke_count, address)) {
        return false;
    }

    // Write the complement as we're simulating flash memory -- 0xFF means 0x00
    std::size_t index = address / BACKING_STORE_WRITE_SIZE;
    backing_storage[index].set(~value);

    // Keep track of the write log so that we can verify during tests
    append_log(address, value);

    // Keep track of the total number of writes into the backing store
    ++backing_total_write_count;

    return true;
}

bool MockBackingStore::lock(void) {
    ++backing_lock_invoke_count;

    EXPECT_FALSE(is_locked()) << "Attempted to lock but was not unlocked";
    locked = true;

    if (lock_success_callback) {
        return lock_success_callback(backing_lock_invoke_count);
    }
    return true;
}

bool MockBackingStore::read(uint32_t address, backing_store_int_t& value) const {
    // precondition: value's buffer size already matches BACKING_STORE_WRITE_SIZE
    EXPECT_TRUE(address % BACKING_STORE_WRITE_SIZE == 0) << "Supplied address was not aligned with the backing store integral size";
    EXPECT_TRUE(address + BACKING_STORE_WRITE_SIZE <= WEAR_LEVELING_BACKING_SIZE) << "Address would result of out-of-bounds access";

    // Read and take the complement as we're simulating flash memory -- 0xFF means 0x00
    std::size_t index = address / BACKING_STORE_WRITE_SIZE;
    value             = ~backing_storage[index].get();

    return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Backing Implementation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern "C" bool backing_store_init(void) {
    return MockBackingStore::Instance().init();
}

extern "C" bool backing_store_unlock(void) {
    return MockBackingStore::Instance().unlock();
}

extern "C" bool backing_store_erase(void) {
    return MockBackingStore::Instance().erase();
}

extern "C" bool backing_store_write(uint32_t address, backing_store_int_t value) {
    return MockBackingStore::Instance().write(address, value);
}

extern "C" bool backing_store_lock(void) {
    return MockBackingStore::Instance().lock();
}

extern "C" bool backing_store_read(uint32_t address, backing_store_int_t* value) {
    return MockBackingStore::Instance().read(address, *value);
}