Software APIs
flash_init_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 
12 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
13 #include "sw/device/lib/testing/pinmux_testutils.h"
14 #include "sw/device/lib/testing/test_framework/check.h"
15 #include "sw/device/lib/testing/test_framework/status.h"
16 
17 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
18 
19 static dif_uart_t uart0;
20 static dif_flash_ctrl_state_t flash_state;
21 
22 enum {
23  kFlashInfoPageIdCreatorSecret = 1,
24  kFlashInfoPageIdOwnerSecret = 2,
25  kFlashInfoPageIdIsoPart = 3,
26  kFlashInfoBank = 0,
27  kFlashDataRegionZero = 0,
28  kFlashDataRegionOne = 1,
29  kRegionBaseBank0Page0Index = 0,
30  kRegionBaseBank1Page0Index = 256,
31  kPartitionId = 0,
32  kRegionSize = 1,
33  kPageSize = 2048,
34  kNumTestWords = 16,
35  kNumTestBytes = kNumTestWords * sizeof(uint32_t),
36 };
37 
38 enum {
39  kTestPhaseCheckUnscrambledInit0 = 0,
40  kTestPhaseCheckUnscrambledInit1 = 1,
41  kTestPhaseCheckUnscrambledInit2 = 2,
42  kTestPhaseCheckScrambledInit0 = 3,
43  kTestPhaseCheckScrambledInit1 = 4,
44  kTestPhaseCheckBackdoor0 = 5,
45  kTestPhaseCheckBackdoor1 = 6,
46  kTestPhaseKeymgrPrep = 7,
47  kTestPhaseKeymgrTest0 = 8,
48  kTestPhaseKeymgrTest1 = 9,
49 };
50 
51 enum {
52  kNumRegions = 5,
53  kAddressBank0Page0Data = 0,
54  kAddressBank1Page0Data = 1,
55  kAddressCreatorSecret = 2,
56  kAddressOwnerSecret = 3,
57  kAddressIsoPart = 4,
58 };
59 
60 enum {
61  kCreatorSecretDataRetSramAddress = 0,
62  kOwnerSecretDataRetSramAddress =
63  kCreatorSecretDataRetSramAddress + (kNumTestWords * sizeof(uint32_t)),
64  kIsoPartDataRetSramAddress =
65  kOwnerSecretDataRetSramAddress + (kNumTestWords * sizeof(uint32_t)),
66  kBank0Page0DataRetSramAddress =
67  kIsoPartDataRetSramAddress + (kNumTestWords * sizeof(uint32_t)),
68  kBank1Page0DataRetSramAddress =
69  kBank0Page0DataRetSramAddress + (kNumTestWords * sizeof(uint32_t)),
70 };
71 
72 // The test phase is updated by the testbench with a symbol backdoor overwrite.
73 static volatile const uint8_t kTestPhase = 0;
74 
75 // The test data is updated by the testbench by filling the retention SRAM
76 // which can then be copied and used locally.
77 static uint32_t kCreatorSecretData[kNumTestWords];
78 static uint32_t kOwnerSecretData[kNumTestWords];
79 static uint32_t kIsoPartData[kNumTestWords];
80 static uint32_t kBank0Page0Data[kNumTestWords];
81 static uint32_t kBank1Page0Data[kNumTestWords];
82 
83 static uint32_t region_addresses[kNumRegions];
84 
85 static void setup_unscrambled_regions(void) {
86  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_setup(
87  &flash_state, kRegionBaseBank0Page0Index, kFlashDataRegionZero,
88  kRegionSize, &region_addresses[kAddressBank0Page0Data]));
89  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_setup(
90  &flash_state, kRegionBaseBank1Page0Index, kFlashDataRegionOne,
91  kRegionSize, &region_addresses[kAddressBank1Page0Data]));
92  CHECK_STATUS_OK(flash_ctrl_testutils_info_region_setup(
93  &flash_state, kFlashInfoPageIdCreatorSecret, kFlashInfoBank, kPartitionId,
94  &region_addresses[kAddressCreatorSecret]));
95  CHECK_STATUS_OK(flash_ctrl_testutils_info_region_setup(
96  &flash_state, kFlashInfoPageIdOwnerSecret, kFlashInfoBank, kPartitionId,
97  &region_addresses[kAddressOwnerSecret]));
98 
99  CHECK_STATUS_OK(flash_ctrl_testutils_info_region_setup(
100  &flash_state, kFlashInfoPageIdIsoPart, kFlashInfoBank, kPartitionId,
101  &region_addresses[kAddressIsoPart]));
102 }
103 
104 static void setup_scrambled_regions(void) {
105  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_scrambled_setup(
106  &flash_state, kRegionBaseBank0Page0Index, kFlashDataRegionZero,
107  kRegionSize, &region_addresses[kAddressBank0Page0Data]));
108  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_scrambled_setup(
109  &flash_state, kRegionBaseBank1Page0Index, kFlashDataRegionOne,
110  kRegionSize, &region_addresses[kAddressBank1Page0Data]));
111  CHECK_STATUS_OK(flash_ctrl_testutils_info_region_scrambled_setup(
112  &flash_state, kFlashInfoPageIdCreatorSecret, kFlashInfoBank, kPartitionId,
113  &region_addresses[kAddressCreatorSecret]));
114  CHECK_STATUS_OK(flash_ctrl_testutils_info_region_scrambled_setup(
115  &flash_state, kFlashInfoPageIdOwnerSecret, kFlashInfoBank, kPartitionId,
116  &region_addresses[kAddressOwnerSecret]));
117  CHECK_STATUS_OK(flash_ctrl_testutils_info_region_scrambled_setup(
118  &flash_state, kFlashInfoPageIdIsoPart, kFlashInfoBank, kPartitionId,
119  &region_addresses[kAddressIsoPart]));
120 }
121 
122 static void erase_and_write_regions(void) {
123  CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page(
124  &flash_state, region_addresses[kAddressBank0Page0Data], kPartitionId,
125  kBank0Page0Data, kDifFlashCtrlPartitionTypeData, kNumTestWords));
126  CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page(
127  &flash_state, region_addresses[kAddressBank1Page0Data], kPartitionId,
128  kBank1Page0Data, kDifFlashCtrlPartitionTypeData, kNumTestWords));
129  CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page(
130  &flash_state, region_addresses[kAddressCreatorSecret], kPartitionId,
131  kCreatorSecretData, kDifFlashCtrlPartitionTypeInfo, kNumTestWords));
132  CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page(
133  &flash_state, region_addresses[kAddressOwnerSecret], kPartitionId,
134  kOwnerSecretData, kDifFlashCtrlPartitionTypeInfo, kNumTestWords));
135  CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page(
136  &flash_state, region_addresses[kAddressIsoPart], kPartitionId,
137  kIsoPartData, kDifFlashCtrlPartitionTypeInfo, kNumTestWords));
138 }
139 
140 static void read_and_check_host_if(uint32_t addr, const uint32_t *check_data) {
141  uint32_t host_data[kNumTestWords];
144  kNumTestBytes);
145  CHECK_ARRAYS_EQ(host_data, check_data, kNumTestWords);
146 }
147 
148 static void check_readback_data_match(void) {
149  uint32_t readback_data[kNumTestWords];
150  CHECK_STATUS_OK(flash_ctrl_testutils_read(
151  &flash_state, region_addresses[kAddressBank0Page0Data], kPartitionId,
152  readback_data, kDifFlashCtrlPartitionTypeData, kNumTestWords, 0));
153  CHECK_ARRAYS_EQ(readback_data, kBank0Page0Data, kNumTestWords);
154  CHECK_STATUS_OK(flash_ctrl_testutils_read(
155  &flash_state, region_addresses[kAddressBank1Page0Data], kPartitionId,
156  readback_data, kDifFlashCtrlPartitionTypeData, kNumTestWords, 0));
157  CHECK_ARRAYS_EQ(readback_data, kBank1Page0Data, kNumTestWords);
158  CHECK_STATUS_OK(flash_ctrl_testutils_read(
159  &flash_state, region_addresses[kAddressCreatorSecret], kPartitionId,
160  readback_data, kDifFlashCtrlPartitionTypeInfo, kNumTestWords, 0));
161  CHECK_ARRAYS_EQ(readback_data, kCreatorSecretData, kNumTestWords);
162  CHECK_STATUS_OK(flash_ctrl_testutils_read(
163  &flash_state, region_addresses[kAddressOwnerSecret], kPartitionId,
164  readback_data, kDifFlashCtrlPartitionTypeInfo, kNumTestWords, 0));
165  CHECK_ARRAYS_EQ(readback_data, kOwnerSecretData, kNumTestWords);
166  CHECK_STATUS_OK(flash_ctrl_testutils_read(
167  &flash_state, region_addresses[kAddressIsoPart], kPartitionId,
168  readback_data, kDifFlashCtrlPartitionTypeInfo, kNumTestWords, 0));
169  CHECK_ARRAYS_EQ(readback_data, kIsoPartData, kNumTestWords);
170 
171  read_and_check_host_if(kRegionBaseBank0Page0Index, kBank0Page0Data);
172  read_and_check_host_if(kPageSize * kRegionBaseBank1Page0Index,
173  kBank1Page0Data);
174 }
175 
176 static bool transaction_end_check_read_error(void) {
178  while (true) {
179  dif_result_t dif_result = dif_flash_ctrl_end(&flash_state, &output);
180  CHECK(dif_result != kDifBadArg);
181  CHECK(dif_result != kDifError);
182  if (dif_result == kDifOk) {
183  break;
184  }
185  }
186  bool is_read_error = !output.error_code.codes.memory_properties_error &
187  output.error_code.codes.read_error &
191  CHECK_DIF_OK(
192  dif_flash_ctrl_clear_error_codes(&flash_state, output.error_code.codes));
193  return is_read_error;
194 }
195 
196 static void check_readback_fail(void) {
197  uint32_t readback_data[kNumTestWords];
198 
199  dif_flash_ctrl_transaction_t transaction = {
200  .byte_address = region_addresses[kAddressBank0Page0Data],
201  .op = kDifFlashCtrlOpRead,
202  .partition_type = kDifFlashCtrlPartitionTypeData,
203  .partition_id = kPartitionId,
204  .word_count = kNumTestWords};
205  CHECK_DIF_OK(dif_flash_ctrl_start(&flash_state, transaction));
206  CHECK_DIF_OK(
207  dif_flash_ctrl_read_fifo_pop(&flash_state, kNumTestWords, readback_data));
208  CHECK(transaction_end_check_read_error());
209 
210  transaction.byte_address = region_addresses[kAddressBank1Page0Data];
211  CHECK_DIF_OK(dif_flash_ctrl_start(&flash_state, transaction));
212  CHECK_DIF_OK(
213  dif_flash_ctrl_read_fifo_pop(&flash_state, kNumTestWords, readback_data));
214  CHECK(transaction_end_check_read_error());
215 
216  transaction.partition_type = kDifFlashCtrlPartitionTypeInfo;
217  transaction.byte_address = region_addresses[kAddressCreatorSecret];
218  CHECK_DIF_OK(dif_flash_ctrl_start(&flash_state, transaction));
219  CHECK_DIF_OK(
220  dif_flash_ctrl_read_fifo_pop(&flash_state, kNumTestWords, readback_data));
221  CHECK(transaction_end_check_read_error());
222 
223  transaction.byte_address = region_addresses[kAddressOwnerSecret];
224  CHECK_DIF_OK(dif_flash_ctrl_start(&flash_state, transaction));
225  CHECK_DIF_OK(
226  dif_flash_ctrl_read_fifo_pop(&flash_state, kNumTestWords, readback_data));
227  CHECK(transaction_end_check_read_error());
228 
229  transaction.byte_address = region_addresses[kAddressIsoPart];
230  CHECK_DIF_OK(dif_flash_ctrl_start(&flash_state, transaction));
231  CHECK_DIF_OK(
232  dif_flash_ctrl_read_fifo_pop(&flash_state, kNumTestWords, readback_data));
233  CHECK(transaction_end_check_read_error());
234 }
235 
236 static void flash_init(void) {
237  CHECK_DIF_OK(dif_flash_ctrl_start_controller_init(&flash_state));
239  while (true) {
240  CHECK_DIF_OK(dif_flash_ctrl_get_status(&flash_state, &flash_ctrl_status));
241  if (flash_ctrl_status.controller_init_wip == false) {
242  break;
243  }
244  }
245 }
246 
247 static void check_unscrambled_init(void) {
248  setup_unscrambled_regions();
249  erase_and_write_regions();
250  flash_init();
251  check_readback_data_match();
252  test_status_set(kTestStatusInWfi);
254 }
255 
256 static void check_scrambled_init(void) {
257  setup_scrambled_regions();
258  erase_and_write_regions();
259  check_readback_data_match();
260  flash_init();
261  check_readback_fail();
262  test_status_set(kTestStatusInWfi);
264 }
265 
266 static void check_scrambled_backdoor_data(void) {
267  setup_scrambled_regions();
268  flash_init();
269  check_readback_data_match();
270  test_status_set(kTestStatusInWfi);
272 }
273 
274 bool rom_test_main(void) {
275  // We need to set the test status as "in test" to indicate to the test code
276  // has been reached, even though this test is also in the "boot ROM".
277  test_status_set(kTestStatusInTest);
278  dif_pinmux_t pinmux;
279  CHECK_DIF_OK(dif_pinmux_init(
281  pinmux_testutils_init(&pinmux);
282 
283  // We need to initialize the UART regardless if we LOG any messages, since
284  // Verilator and FPGA platforms use the UART to communicate the test results.
285  if (kDeviceType != kDeviceSimDV) {
286  CHECK_DIF_OK(dif_uart_init(
288  CHECK(kUartBaudrate <= UINT32_MAX, "kUartBaudrate must fit in uint32_t");
289  CHECK(kClockFreqPeripheralHz <= UINT32_MAX,
290  "kClockFreqPeripheralHz must fit in uint32_t");
291  CHECK_DIF_OK(dif_uart_configure(
292  &uart0, (dif_uart_config_t){
293  .baudrate = (uint32_t)kUartBaudrate,
294  .clk_freq_hz = (uint32_t)kClockFreqPeripheralHz,
295  .parity_enable = kDifToggleDisabled,
296  .parity = kDifUartParityEven,
297  .tx_enable = kDifToggleEnabled,
298  .rx_enable = kDifToggleEnabled,
299  }));
300  base_uart_stdout(&uart0);
301  }
302 
303  // Test code.
304  mmio_region_t sram_region_ret_base_addr =
306 
307  mmio_region_memcpy_from_mmio32(sram_region_ret_base_addr,
308  kCreatorSecretDataRetSramAddress,
309  &kCreatorSecretData, kNumTestBytes);
310  mmio_region_memcpy_from_mmio32(sram_region_ret_base_addr,
311  kOwnerSecretDataRetSramAddress,
312  &kOwnerSecretData, kNumTestBytes);
313  mmio_region_memcpy_from_mmio32(sram_region_ret_base_addr,
314  kIsoPartDataRetSramAddress, &kIsoPartData,
315  kNumTestBytes);
316  mmio_region_memcpy_from_mmio32(sram_region_ret_base_addr,
317  kBank0Page0DataRetSramAddress,
318  &kBank0Page0Data, kNumTestBytes);
319  mmio_region_memcpy_from_mmio32(sram_region_ret_base_addr,
320  kBank1Page0DataRetSramAddress,
321  &kBank1Page0Data, kNumTestBytes);
322 
323  CHECK_DIF_OK(dif_flash_ctrl_init_state(
324  &flash_state,
326 
327  switch (kTestPhase) {
328  case kTestPhaseCheckUnscrambledInit0:
329  case kTestPhaseCheckUnscrambledInit1:
330  case kTestPhaseCheckUnscrambledInit2:
331  check_unscrambled_init();
332  break;
333  case kTestPhaseCheckScrambledInit0:
334  case kTestPhaseCheckScrambledInit1:
335  check_scrambled_init();
336  break;
337  case kTestPhaseCheckBackdoor0:
338  case kTestPhaseCheckBackdoor1:
339  check_scrambled_backdoor_data();
340  break;
341  case kTestPhaseKeymgrPrep:
342  case kTestPhaseKeymgrTest0:
343  case kTestPhaseKeymgrTest1:
344  flash_init();
345  test_status_set(kTestStatusInWfi);
347  break;
348  default:
349  break;
350  }
351  return true;
352 }