Software APIs
flash_ctrl_mem_protection_test.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 
11 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
12 #include "sw/device/lib/testing/test_framework/check.h"
14 
15 #include "flash_ctrl_regs.h"
17 
18 /**
19  * FLASH_CTRL memory protection test
20  *
21  * This test checks multiple memory protection regions and priority in case
22  * any regions overlap.
23  *
24  * Test programs regions as follows.
25  *
26  * region | bank | page start | page end | rd_en | prog_en | erase_en |
27  * -------------------------------------------------------------------:
28  * 0 | 1 | 12 | 13 | True | False | True |
29  * 3 | 1 | 11 | 14 | False | True | True |
30  * 7 | 1 | 10 | 15 | True | True | True |
31  *
32  * As you see, these regions intentionally overlap each other.
33  * For any overlaping regions the lower region has priority.
34  * To check this attribute, test will program higher region first.
35  * Test programs Region 7, 3 and 0 in order and checks
36  * write and read back based on each region's attribute.
37  */
38 OTTF_DEFINE_TEST_CONFIG();
39 
40 static dif_flash_ctrl_state_t flash;
41 
42 typedef struct test {
43  /**
44  * Memory protection(MP) region number
45  */
46  uint32_t region_index;
47  /**
48  * Write data per each page.
49  * Full size of write data per page (2KB) is generated by
50  * loop:
51  * j = 0; j < words_per_page (256); j++
52  * randomdata + j
53  */
54  uint32_t randomdata[6];
55  /**
56  * Page start index per each MP region.
57  */
58  uint32_t page_start;
59  /**
60  * Write permission per each page.
61  */
63  /**
64  * Read permission per each page.
65  */
66  bool read_permission[6];
67  /**
68  * MP region config property.
69  */
71 } test_t;
72 
73 #define BANK1_START_PAGE 256
74 #define START_PAGE_ADDR \
75  TOP_EARLGREY_FLASH_CTRL_MEM_BASE_ADDR + FLASH_CTRL_PARAM_BYTES_PER_BANK
76 
77 static const test_t kRegion[] = {
78  {.region_index = 0,
79  .randomdata = {0x77777770, 0x66666660},
80  .page_start = 12,
81  .write_permission = {false, false},
82  .read_permission = {true, true},
83  .data_region =
84  {
85  .base = BANK1_START_PAGE + 12,
86  .size = 2,
87  .properties =
88  {
89  .rd_en = kMultiBitBool4True,
90  .prog_en = kMultiBitBool4False,
91  .erase_en = kMultiBitBool4True,
92  .scramble_en = kMultiBitBool4True,
93  .ecc_en = kMultiBitBool4True,
94  .high_endurance_en = kMultiBitBool4False,
95  },
96  }},
97  {.region_index = 3,
98  .randomdata = {0x88888880, 0x77777770, 0x66666660, 0x55555550},
99  .page_start = 11,
100  .write_permission = {true, true, true, true},
101  .read_permission = {false, false, false, false},
102  .data_region =
103  {
104  .base = BANK1_START_PAGE + 11,
105  .size = 4,
106  .properties =
107  {
108  .rd_en = kMultiBitBool4False,
109  .prog_en = kMultiBitBool4True,
110  .erase_en = kMultiBitBool4True,
111  .scramble_en = kMultiBitBool4True,
112  .ecc_en = kMultiBitBool4True,
113  .high_endurance_en = kMultiBitBool4False,
114  },
115  }},
116  {.region_index = 7,
117  .randomdata = {0xaaaaaaa0, 0xbbbbbbb0, 0xccccccc0, 0xddddddd0, 0xeeeeeee0,
118  0x99999990},
119  .page_start = 10,
120  .write_permission = {true, true, true, true, true, true},
121  .read_permission = {true, true, true, true, true, true},
122  .data_region =
123  {
124  .base = BANK1_START_PAGE + 10,
125  .size = 6,
126  .properties =
127  {
128  .rd_en = kMultiBitBool4True,
129  .prog_en = kMultiBitBool4True,
130  .erase_en = kMultiBitBool4True,
131  .scramble_en = kMultiBitBool4True,
132  .ecc_en = kMultiBitBool4True,
133  .high_endurance_en = kMultiBitBool4False,
134  },
135  }},
136 };
137 
138 /**
139  * Memory write and readback test
140  * For each MP region, this function check write and read permission
141  * based on MP region properties and priority of each MP region.
142  */
143 static void test_mem_access(test_t region) {
144  uint32_t page_size = region.data_region.size;
145  uintptr_t start_epage =
146  (uintptr_t)(START_PAGE_ADDR +
147  FLASH_CTRL_PARAM_BYTES_PER_PAGE * region.page_start);
148  uint32_t wdata[FLASH_CTRL_PARAM_WORDS_PER_PAGE];
149 
150  for (uint32_t i = 0; i < page_size; i++) {
151  for (size_t j = 0; j < ARRAYSIZE(wdata); j++)
152  wdata[j] = region.randomdata[i] + j;
153  if (region.write_permission[i]) {
154  CHECK_STATUS_OK(flash_ctrl_testutils_erase_page(
155  &flash, start_epage,
156  /*partition_id=*/0, kDifFlashCtrlPartitionTypeData));
157  CHECK_STATUS_OK(flash_ctrl_testutils_write(&flash, start_epage,
158  /*partition_id=*/0, wdata,
159  kDifFlashCtrlPartitionTypeData,
160  ARRAYSIZE(wdata)));
161  LOG_INFO("test_mem_access: page %d write complete",
162  region.page_start + i);
163  } else {
164  CHECK_STATUS_NOT_OK(flash_ctrl_testutils_write(
165  &flash, start_epage,
166  /*partition_id=*/0, wdata, kDifFlashCtrlPartitionTypeData,
167  ARRAYSIZE(wdata)));
168  LOG_INFO("test_mem_access: page %d write is not allowed",
169  region.page_start + i);
170  }
171  uint32_t rdata[FLASH_CTRL_PARAM_WORDS_PER_PAGE];
172 
173  if (region.read_permission[i]) {
174  CHECK_STATUS_OK(flash_ctrl_testutils_read(
175  &flash, start_epage, /*partition_id=*/0, rdata,
176  kDifFlashCtrlPartitionTypeData, ARRAYSIZE(rdata),
177  /*delay=*/1));
178  CHECK_ARRAYS_EQ(rdata, wdata, ARRAYSIZE(rdata));
179  LOG_INFO("test_mem_access: page %d read check complete",
180  region.page_start + i);
181  } else {
182  CHECK_STATUS_NOT_OK(flash_ctrl_testutils_read(
183  &flash, start_epage, /*partition_id=*/0, rdata,
184  kDifFlashCtrlPartitionTypeData, ARRAYSIZE(rdata),
185  /*delay=*/1));
186  LOG_INFO("test_mem_access: page %d read is not allowed",
187  region.page_start + i);
188  }
189  start_epage += (uintptr_t)FLASH_CTRL_PARAM_BYTES_PER_PAGE;
190  }
191 }
192 
193 bool test_main(void) {
194  LOG_INFO("flash mp test start!");
195  CHECK_DIF_OK(dif_flash_ctrl_init_state(
197 
198  // Set up default access for data partitions.
199  // In silicon, rom_ext will set default region access.
200  // After that, it cannot be updated.
201  if (kDeviceType != kDeviceSilicon) {
202  CHECK_STATUS_OK(flash_ctrl_testutils_default_region_access(
203  &flash, /*rd_en=*/true, /*prog_en=*/true, /*erase_en=*/true,
204  /*scramble_en=*/false, /*ecc_en=*/false, /*high_endurance_en=*/false));
205  }
206  // Program starts from kRegion[2], kRegion[1], and kRegion[0] in order.
207  for (int i = 2; i >= 0; i--) {
209  &flash, kRegion[i].region_index, kRegion[i].data_region));
211  &flash, kRegion[i].region_index, kDifToggleEnabled));
212  test_mem_access(kRegion[i]);
213  }
214 
215  LOG_INFO("test done");
216  return true;
217 }