Software APIs
nv_counter_testutils.c
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 
5 #include "sw/device/lib/testing/nv_counter_testutils.h"
6 
7 #include <assert.h>
8 #include <stdbool.h>
9 #include <stdint.h>
10 
12 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
14 
15 #include "flash_ctrl_regs.h" // Generated.
17 
18 enum {
19  kNonVolatileCounterFlashWords = 256,
20 };
21 static_assert(kNonVolatileCounterFlashWords ==
22  kFlashCtrlTestUtilsCounterMaxCount,
23  "Word count must be equal to max count.");
24 static_assert(
25  FLASH_CTRL_PARAM_BYTES_PER_WORD == sizeof(uint64_t),
26  "Elements of the counter array must be the same size as a flash word");
27 extern char _non_volatile_counter_flash_words[];
28 
29 OT_SET_BSS_SECTION(".non_volatile_counter_0",
30  uint64_t nv_counter_0[kNonVolatileCounterFlashWords];)
31 OT_SET_BSS_SECTION(".non_volatile_counter_1",
32  uint64_t nv_counter_1[kNonVolatileCounterFlashWords];)
33 OT_SET_BSS_SECTION(".non_volatile_counter_2",
34  uint64_t nv_counter_2[kNonVolatileCounterFlashWords];)
35 OT_SET_BSS_SECTION(".non_volatile_counter_3",
36  uint64_t nv_counter_3[kNonVolatileCounterFlashWords];)
37 
38 static uint64_t *const kNvCounters[] = {
39  nv_counter_0,
40  nv_counter_1,
41  nv_counter_2,
42  nv_counter_3,
43 };
44 
45 status_t flash_ctrl_testutils_counter_get(size_t counter, uint32_t *value) {
46  TRY_CHECK(value != NULL);
47  TRY_CHECK(counter < ARRAYSIZE(kNvCounters));
48  TRY_CHECK((uint32_t)&_non_volatile_counter_flash_words ==
49  kNonVolatileCounterFlashWords);
50 
51  // Use a reverse loop since `flash_ctrl_testutils_counter_set_at_least()` can
52  // introduce gaps.
53  size_t i = kNonVolatileCounterFlashWords - 1;
54  for (; i < kNonVolatileCounterFlashWords; --i) {
55  if (kNvCounters[counter][i] == 0) {
56  break;
57  }
58  }
59  *value = i + 1;
60  return OK_STATUS();
61 }
62 
63 status_t flash_ctrl_testutils_counter_increment(
64  dif_flash_ctrl_state_t *flash_state, size_t counter) {
65  size_t i;
66  TRY(flash_ctrl_testutils_counter_get(counter, &i));
67  TRY_CHECK(i < kNonVolatileCounterFlashWords,
68  "Non-volatile counter %u is at its maximum", counter);
69  TRY(flash_ctrl_testutils_counter_set_at_least(flash_state, counter, i + 1));
70  uint32_t value;
71  TRY(flash_ctrl_testutils_counter_get(counter, &value));
72  TRY_CHECK(value == i + 1, "Counter increment failed");
73  return OK_STATUS();
74 }
75 
76 status_t flash_ctrl_testutils_counter_set_at_least(
77  dif_flash_ctrl_state_t *flash_state, size_t counter, uint32_t val) {
78  TRY_CHECK(val <= kNonVolatileCounterFlashWords,
79  "Non-volatile counter %u new value %u > max value %u", counter, val,
80  kNonVolatileCounterFlashWords);
81  if (val == 0) {
82  return OK_STATUS();
83  }
84  uint32_t new_val[FLASH_CTRL_PARAM_BYTES_PER_WORD / sizeof(uint32_t)] = {0, 0};
85  return flash_ctrl_testutils_write(flash_state,
86  (uint32_t)&kNvCounters[counter][val - 1] -
88  0, new_val, kDifFlashCtrlPartitionTypeData,
89  ARRAYSIZE(new_val));
90 }
91 
92 // At the beginning of the simulation (Verilator, VCS,etc.),
93 // the content of the flash might be all-zeros, and thus,
94 // the NVM counter's inital value might be 256.
95 // In that case, flash_ctrl_testutils_counter_set_at_least() will not increment
96 // This function can be used to initialize a NVM counter to zero by filling
97 // its flash region with non-zero values.
98 status_t flash_ctrl_testutils_counter_init_zero(
99  dif_flash_ctrl_state_t *flash_state, size_t counter) {
100  uint32_t new_val[FLASH_CTRL_PARAM_BYTES_PER_WORD / sizeof(uint32_t)] = {0xaa,
101  0xbb};
102  for (int ii = 0; ii < kNonVolatileCounterFlashWords; ii++) {
103  TRY(flash_ctrl_testutils_erase_and_write_page(
104  flash_state,
105  (uint32_t)&kNvCounters[counter][ii] -
107  0, new_val, kDifFlashCtrlPartitionTypeData, ARRAYSIZE(new_val)));
108  }
109  return OK_STATUS();
110 }