Software APIs
sec_mmio_unittest.cc
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
7 #include <array>
8 #include <cstdlib>
9 #include <vector>
10 
11 #include "gtest/gtest.h"
12 #include "sw/device/lib/base/mock_abs_mmio.h"
13 #include "sw/device/silicon_creator/lib/error.h"
14 #include "sw/device/silicon_creator/testing/rom_test.h"
15 
16 namespace sec_mmio_unittest {
17 namespace {
18 using ::testing::Each;
19 using ::testing::ElementsAreArray;
20 using ::testing::Eq;
21 
23  protected:
24  void SetUp() override { sec_mmio_init(); }
26  rom_test::MockAbsMmio mmio_;
27 };
28 
29 TEST_F(SecMmioTest, Initialize) {
30  // Write non-zero values to critical fields before calling `sec_mmio_init()`.
31  ctx_->check_count = 1;
32  ctx_->expected_write_count = 1;
33  ctx_->last_index = 1;
34  ctx_->write_count = 1;
35  ctx_->addrs[0] = 0;
36  sec_mmio_init();
37 
38  EXPECT_EQ(ctx_->check_count, 0);
39  EXPECT_EQ(ctx_->expected_write_count, 0);
40  EXPECT_EQ(ctx_->last_index, 0);
41  EXPECT_EQ(ctx_->write_count, 0);
42  EXPECT_THAT(ctx_->addrs, Each(Eq(UINT32_MAX)));
43  EXPECT_THAT(ctx_->values, Each(Eq(UINT32_MAX)));
44 }
45 
46 TEST_F(SecMmioTest, NextStageInitialize) {
47  // Ensure the register file size is greater than zero to ensure checks are
48  // performed on non-zero sized arrays.
49  static_assert(kSecMmioRegFileSize > 2,
50  "kSecMmioRegFileSize must be greater than 2");
51  std::array<uint32_t, kSecMmioRegFileSize> expected_addrs;
52  std::array<uint32_t, kSecMmioRegFileSize> expected_values;
53 
54  // Prefill data to simulate a pre-initialization conditions. Use different
55  // values for `addr` and `values` to ensure the test checks are specific for
56  // each array.
57  for (size_t i = 0; i < kSecMmioRegFileSize; ++i) {
58  ctx_->addrs[i] = i ^ 0xa;
59  ctx_->values[i] = i ^ 0x5;
60  expected_addrs[i] = ctx_->addrs[i];
61  expected_values[i] = ctx_->values[i];
62  }
63 
64  ctx_->check_count = 5;
65  ctx_->expected_write_count = 6;
66  ctx_->write_count = 6;
67 
68  const uint32_t kExpectedWriteCount = kSecMmioRegFileSize / 2;
69  ctx_->last_index = kExpectedWriteCount;
70 
71  for (size_t i = kExpectedWriteCount; i < kSecMmioRegFileSize; ++i) {
72  expected_addrs[i] = UINT32_MAX;
73  expected_values[i] = UINT32_MAX;
74  }
75 
77 
78  EXPECT_EQ(ctx_->write_count, 6);
79  EXPECT_EQ(ctx_->expected_write_count, 6);
80  EXPECT_EQ(ctx_->last_index, kExpectedWriteCount);
81  EXPECT_EQ(ctx_->check_count, 0);
82  EXPECT_THAT(ctx_->addrs, ElementsAreArray(expected_addrs));
83  EXPECT_THAT(ctx_->values, ElementsAreArray(expected_values));
84 }
85 
86 TEST_F(SecMmioTest, Read32OrDie) {
87  EXPECT_ABS_READ32(0, 0x12345678);
88  EXPECT_ABS_READ32(0, 0x12345678);
89  EXPECT_EQ(sec_mmio_read32(0), 0x12345678);
90 
91  EXPECT_ABS_READ32(4, 0x87654321);
92  EXPECT_ABS_READ32(4, 0x87654321);
93  EXPECT_EQ(sec_mmio_read32(4), 0x87654321);
94 
95  EXPECT_ABS_READ32(0, 0x87654321);
96  EXPECT_ABS_READ32(0, 0x87654321);
97  EXPECT_EQ(sec_mmio_read32(0), 0x87654321);
98 
99  // Two of the operations were targeting the same offset, so we only expect two
100  // operations and zero shutdown attempts.
101  EXPECT_EQ(ctx_->write_count, 0);
102  EXPECT_EQ(ctx_->last_index, 2);
103 }
104 
105 TEST_F(SecMmioTest, Write32) {
106  EXPECT_ABS_WRITE32(0, 0x12345678);
107  EXPECT_ABS_READ32(0, 0x12345678);
108  sec_mmio_write32(0, 0x12345678);
109  EXPECT_EQ(ctx_->write_count, 1);
110 
111  EXPECT_ABS_WRITE32(4, 0x87654321);
112  EXPECT_ABS_READ32(4, 0x87654321);
113  sec_mmio_write32(4, 0x87654321);
114  EXPECT_EQ(ctx_->write_count, 2);
115 
116  EXPECT_ABS_WRITE32(0, 0x87654321);
117  EXPECT_ABS_READ32(0, 0x87654321);
118  sec_mmio_write32(0, 0x87654321);
119  EXPECT_EQ(ctx_->write_count, 3);
120 
121  // Two of the operations were targeting the same offset, so we only expect two
122  // operations.
123  EXPECT_EQ(ctx_->last_index, 2);
124 }
125 
126 TEST_F(SecMmioTest, CheckValues) {
127  EXPECT_ABS_WRITE32(0, 0x12345678);
128  EXPECT_ABS_READ32(0, 0x12345678);
129  sec_mmio_write32(0, 0x12345678);
130 
131  EXPECT_ABS_WRITE32(4, 0x87654321);
132  EXPECT_ABS_READ32(4, 0x87654321);
133  sec_mmio_write32(4, 0x87654321);
134 
135  EXPECT_ABS_WRITE32(8, 0);
136  EXPECT_ABS_READ32(8, 0);
137  sec_mmio_write32(8, 0);
138 
139  // Test an expected value modification which gets updated by a read.
140  EXPECT_ABS_READ32(8, 0xa5a5a5a5);
141  EXPECT_ABS_READ32(8, 0xa5a5a5a5);
142  EXPECT_EQ(sec_mmio_read32(8), 0xa5a5a5a5);
143 
144  // The expected permutation order for rnd_offset=0
145  EXPECT_ABS_READ32(0, 0x12345678);
146  EXPECT_ABS_READ32(4, 0x87654321);
147  EXPECT_ABS_READ32(8, 0xa5a5a5a5);
148  sec_mmio_check_values(/*rnd_offset=*/0);
149  EXPECT_EQ(ctx_->check_count, 1);
150 
151  // The expected permutation order for rnd_offset=0x80000000
152  EXPECT_ABS_READ32(4, 0x87654321);
153  EXPECT_ABS_READ32(8, 0xa5a5a5a5);
154  EXPECT_ABS_READ32(0, 0x12345678);
155  sec_mmio_check_values(/*rnd_offset=*/0x80000000);
156  EXPECT_EQ(ctx_->check_count, 2);
157 
158  // The expected permutation order for rnd_offset=0xf0000000
159  EXPECT_ABS_READ32(8, 0xa5a5a5a5);
160  EXPECT_ABS_READ32(0, 0x12345678);
161  EXPECT_ABS_READ32(4, 0x87654321);
162  sec_mmio_check_values(/*rnd_offset=*/0xf0000000);
163  EXPECT_EQ(ctx_->check_count, 3);
164 }
165 
166 TEST_F(SecMmioTest, CheckCount) {
167  EXPECT_ABS_WRITE32(0, 0x12345678);
168  EXPECT_ABS_READ32(0, 0x12345678);
169  sec_mmio_write32(0, 0x12345678);
171 
172  sec_mmio_check_counters(/*expected_check_count=*/0);
173  sec_mmio_check_counters(/*expected_check_count=*/1);
174  EXPECT_EQ(ctx_->check_count, 2);
175 }
176 
177 // Negative test cases trigger assertions, which are caugth by `EXPECT_DEATH`
178 // calls.
179 class SecMmioDeathTest : public SecMmioTest {};
180 
181 TEST_F(SecMmioDeathTest, Read32OrDieSimulatedFault) {
182  EXPECT_DEATH(
183  {
184  EXPECT_ABS_READ32(0, 0x12345678);
185  EXPECT_ABS_READ32(0, 0);
187  },
188  "");
189 }
190 
191 TEST_F(SecMmioDeathTest, Write32SimulatedFault) {
192  EXPECT_DEATH(
193  {
194  EXPECT_ABS_WRITE32(0, 0x12345678);
195  EXPECT_ABS_READ32(0, 0);
196  sec_mmio_write32(0, 0x12345678);
197  },
198  "");
199 }
200 
201 TEST_F(SecMmioDeathTest, CheckValuesSimulatedFault) {
202  EXPECT_DEATH(
203  {
204  EXPECT_ABS_WRITE32(0, 0x12345678);
205  EXPECT_ABS_READ32(0, 0x12345678);
206  sec_mmio_write32(0, 0x12345678);
207 
208  EXPECT_ABS_READ32(0, 0);
209  sec_mmio_check_values(/*rnd_offset=*/0);
210  },
211  "");
212 }
213 
214 TEST_F(SecMmioDeathTest, CheckCountWriteMismatch) {
215  // The developer forgot to increment the write counter, or an attacker
216  // glitched the sec write operation.
217  EXPECT_DEATH(
218  {
219  EXPECT_ABS_WRITE32(0, 0x12345678);
220  EXPECT_ABS_READ32(0, 0x12345678);
221  sec_mmio_write32(0, 0x12345678);
222  sec_mmio_check_counters(/*expected_check_count=*/0);
223  },
224  "");
225 }
226 
227 } // namespace
228 } // namespace sec_mmio_unittest