Software APIs
flash_ctrl_info_access_lc.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 
9 #include "sw/device/lib/runtime/irq.h"
11 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
12 #include "sw/device/lib/testing/lc_ctrl_testutils.h"
13 #include "sw/device/lib/testing/rv_plic_testutils.h"
14 #include "sw/device/lib/testing/test_framework/check.h"
16 
18 #include "lc_ctrl_regs.h"
19 #include "sw/device/lib/testing/autogen/isr_testutils.h"
20 
21 OTTF_DEFINE_TEST_CONFIG();
22 
23 static dif_lc_ctrl_t lc_ctrl;
24 static dif_rv_plic_t plic0;
25 static dif_flash_ctrl_state_t flash_state;
26 static dif_flash_ctrl_t flash_ctrl;
27 
28 static plic_isr_ctx_t plic_ctx = {
29  .rv_plic = &plic0,
30  .hart_id = kTopEarlgreyPlicTargetIbex0,
31 };
32 
33 static flash_ctrl_isr_ctx_t flash_ctx = {
34  .flash_ctrl = &flash_ctrl,
35  .plic_flash_ctrl_start_irq_id = kTopEarlgreyPlicIrqIdFlashCtrlProgEmpty,
36  .is_only_irq = false,
37 };
38 
39 enum {
40  kFlashInfoBank = 0,
41  kPartitionId = 0,
42  kFlashInfoPageIdCreatorSecret = 1,
43  kFlashInfoPageIdOwnerSecret = 2,
44  kFlashInfoPageIdIsoPart = 3,
45  kInfoSize = 16,
46  kNumIRQs = 5,
47 };
48 
49 static const uint32_t kRandomData1[kInfoSize] = {
50  0xb295d21b, 0xecdfbdcd, 0x67e7ab2d, 0x6f660b08, 0x273bf65c, 0xe80f1695,
51  0x586b80db, 0xc3dba27e, 0xdc124c5d, 0xb01ccd52, 0x815713e1, 0x31a141b2,
52  0x2124be3b, 0x299a6f2a, 0x1f2a4741, 0x1a073cc0,
53 };
54 
55 static const uint32_t kRandomData2[kInfoSize] = {
56  0x69e705a0, 0x65c2ec6b, 0x04b0b634, 0x59313526, 0x1858aee1, 0xd49f3ba9,
57  0x230bcd38, 0xc1eb6b3e, 0x68c15e3b, 0x024d02a9, 0x0b062ae4, 0x334dd155,
58  0x53fdbf8a, 0x3792f1e2, 0xee317161, 0x33b19bf3,
59 };
60 
61 static const uint32_t kRandomData3[kInfoSize] = {
62  0x2b78dbf5, 0x3e6e5a00, 0xbf82c6d5, 0x68d8e33f, 0x9c524bbc, 0xac5beeef,
63  0x1287ca5a, 0x12b61419, 0x872e709f, 0xf91b7c0c, 0x18312a1f, 0x325cef9a,
64  0x19fefa95, 0x4ceb421b, 0xa57d74c4, 0xaf1d723d,
65 };
66 
67 static volatile bool expected_irqs[kNumIRQs];
68 static volatile bool fired_irqs[kNumIRQs];
69 
70 /**
71  * Provides external IRQ handling for this test.
72  *
73  * This function overrides the default OTTF external ISR.
74  */
75 void ottf_external_isr(uint32_t *exc_info) {
76  top_earlgrey_plic_peripheral_t peripheral_serviced;
77  dif_flash_ctrl_irq_t irq_serviced;
78  // Instruct the ISR to mute any status interrupt that is firing.
79  isr_testutils_flash_ctrl_isr(plic_ctx, flash_ctx, true, &peripheral_serviced,
80  &irq_serviced);
81  CHECK(peripheral_serviced == kTopEarlgreyPlicPeripheralFlashCtrl,
82  "Interurpt from unexpected peripheral: %d", peripheral_serviced);
83  fired_irqs[irq_serviced] = true;
84 }
85 
86 /**
87  * Clear the volatile IRQ variables.
88  */
89 static void clear_irq_variables(void) {
90  for (int i = 0; i < kNumIRQs; ++i) {
91  expected_irqs[i] = false;
92  fired_irqs[i] = false;
93  }
94 }
95 
96 /**
97  * Initializes FLASH_CTRL and enables the relevant interrupts.
98  */
99 static void flash_ctrl_init_with_event_irqs(mmio_region_t base_addr,
100  dif_flash_ctrl_state_t *flash_state,
101  dif_flash_ctrl_t *flash_ctrl) {
102  CHECK_DIF_OK(dif_flash_ctrl_init(base_addr, flash_ctrl));
103  CHECK_DIF_OK(dif_flash_ctrl_init_state(flash_state, base_addr));
104 
105  for (dif_flash_ctrl_irq_t i = 0; i < kNumIRQs; ++i) {
106  dif_irq_type_t type;
107  CHECK_DIF_OK(dif_flash_ctrl_irq_get_type(
108  flash_ctrl, kDifFlashCtrlIrqProgEmpty + i, &type));
109  if (type == kDifIrqTypeEvent) {
110  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
111  flash_ctrl, kDifFlashCtrlIrqProgEmpty + i, kDifToggleEnabled));
112  }
113  }
114  clear_irq_variables();
115 }
116 
117 /**
118  * Compares the expected and fired IRQs and clears both.
119  */
120 static void compare_and_clear_irq_variables(void) {
121  for (int i = 0; i < kNumIRQs; ++i) {
122  CHECK(expected_irqs[i] == fired_irqs[i], "expected IRQ mismatch = %d", i);
123  }
124  clear_irq_variables();
125 }
126 
127 /**
128  * Access infomation partition.
129  * If write or read is not allowed, device will generate recoverable alert
130  * (mp_err) and task status of write or read will fail.
131  */
132 static void test_info_part(uint32_t partition_number, const uint32_t *test_data,
133  bool write_allowed, bool read_allowed) {
134  uint32_t address = 0;
135  CHECK_STATUS_OK(flash_ctrl_testutils_info_region_setup(
136  &flash_state, partition_number, kFlashInfoBank, kPartitionId, &address));
137 
138  CHECK_DIF_OK(dif_flash_ctrl_set_prog_fifo_watermark(&flash_state, 0));
139  CHECK_DIF_OK(dif_flash_ctrl_set_read_fifo_watermark(&flash_state, 8));
140  clear_irq_variables();
141 
142  // Write task:
143  // Erase before program the page with test_data.
144  if (write_allowed) {
145  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
146  CHECK_STATUS_OK(flash_ctrl_testutils_erase_page(
147  &flash_state, address, kPartitionId, kDifFlashCtrlPartitionTypeInfo));
148  compare_and_clear_irq_variables();
149 
150  LOG_INFO("partition:%1d erase done", partition_number);
151  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
152  expected_irqs[kDifFlashCtrlIrqProgEmpty] = true;
153  expected_irqs[kDifFlashCtrlIrqProgLvl] = true;
154  // Note: ProgEmpty and ProgLvl interrupts are enabled here and since the
155  // assert by default, they will be serviced and silenced right away. In
156  // order to test them more thoroughly, in this test, we would have to rework
157  // the write operation test utility.
158  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
159  &flash_ctrl, kDifFlashCtrlIrqProgEmpty, kDifToggleEnabled));
160  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
161  &flash_ctrl, kDifFlashCtrlIrqProgLvl, kDifToggleEnabled));
162  CHECK_STATUS_OK(flash_ctrl_testutils_write(
163  &flash_state, address, kPartitionId, test_data,
164  kDifFlashCtrlPartitionTypeInfo, kInfoSize));
165  compare_and_clear_irq_variables();
166  LOG_INFO("partition:%1d write done", partition_number);
167  } else {
168  CHECK_STATUS_NOT_OK(flash_ctrl_testutils_write(
169  &flash_state, address, kPartitionId, test_data,
170  kDifFlashCtrlPartitionTypeInfo, kInfoSize));
171  LOG_INFO("partition:%1d write not allowed", partition_number);
172  }
173 
174  // Read task:
175  // Read page and compared with test_data.
176  uint32_t readback_data[kInfoSize];
177  if (read_allowed) {
178  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
179  expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
180  expected_irqs[kDifFlashCtrlIrqRdFull] = true;
181  // Note: RdLvl and RdFull interrupts are enabled here and as opposed to
182  // ProgEmpty and ProgLvl above, they will be tested correctly, since they
183  // only assert once the FIFO reaches the respective fill levels.
184  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
185  &flash_ctrl, kDifFlashCtrlIrqRdLvl, kDifToggleEnabled));
186  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
187  &flash_ctrl, kDifFlashCtrlIrqRdFull, kDifToggleEnabled));
188  CHECK_STATUS_OK(flash_ctrl_testutils_read(
189  &flash_state, address, kPartitionId, readback_data,
190  kDifFlashCtrlPartitionTypeInfo, kInfoSize, 1));
191  compare_and_clear_irq_variables();
192  CHECK_ARRAYS_EQ(readback_data, test_data, kInfoSize);
193  LOG_INFO("partition:%1d read done", partition_number);
194  } else {
195  CHECK_STATUS_NOT_OK(flash_ctrl_testutils_read(
196  &flash_state, address, kPartitionId, readback_data,
197  kDifFlashCtrlPartitionTypeInfo, kInfoSize, 1));
198  LOG_INFO("partition:%1d read not allowed", partition_number);
199  }
200 }
201 
202 bool test_main(void) {
203  CHECK_DIF_OK(dif_lc_ctrl_init(
205  CHECK_DIF_OK(dif_rv_plic_init(
207 
208  flash_ctrl_init_with_event_irqs(
210  &flash_state, &flash_ctrl);
211  rv_plic_testutils_irq_range_enable(&plic0, plic_ctx.hart_id,
214 
215  // Enable the external IRQ at Ibex.
216  irq_global_ctrl(true);
217  irq_external_ctrl(true);
218 
219  dif_lc_ctrl_id_state_t lc_id_state;
220  dif_lc_ctrl_state_t lc_state;
221  bool personalized = false;
222  // Check if device is personalized.
223  uint32_t reg =
224  mmio_region_read32(lc_ctrl.base_addr, LC_CTRL_LC_ID_STATE_REG_OFFSET);
225  LOG_INFO("id_state: %x", reg);
226 
227  CHECK_DIF_OK(dif_lc_ctrl_get_id_state(&lc_ctrl, &lc_id_state));
228  personalized = (lc_id_state == kDifLcCtrlIdStatePersonalized);
229  LOG_INFO("test: personalized : %d", personalized);
230 
231  // Read lc state and execute info part access test.
232  // Life cycle controlled info partition access is summarized in
233  // (https://opentitan.org/book/hw/ip/lc_ctrl/doc/theory_of_operation.html#
234  // life-cycle-access-control-signals)
235  CHECK_DIF_OK(dif_lc_ctrl_get_state(&lc_ctrl, &lc_state));
236  CHECK_STATUS_OK(lc_ctrl_testutils_lc_state_log(&lc_state));
237 
238  switch (lc_state) {
240  test_info_part(kFlashInfoPageIdCreatorSecret, kRandomData1,
241  /*write_allowed=*/0, /*read_allowed=*/0);
242  test_info_part(kFlashInfoPageIdOwnerSecret, kRandomData2,
243  /*write_allowed=*/0, /*read_allowed=*/0);
244  test_info_part(kFlashInfoPageIdIsoPart, kRandomData3, /*write_allowed=*/1,
245  /*read_allowed=*/0);
246  break;
247  case kDifLcCtrlStateDev:
248  test_info_part(kFlashInfoPageIdCreatorSecret, kRandomData1,
249  /*write_allowed=*/!personalized,
250  /*read_allowed=*/!personalized);
251  test_info_part(kFlashInfoPageIdOwnerSecret, kRandomData2,
252  /*write_allowed=*/1, /*read_allowed=*/1);
253  test_info_part(kFlashInfoPageIdIsoPart, kRandomData3, /*write_allowed=*/1,
254  /*read_allowed=*/0);
255  break;
256  case kDifLcCtrlStateProd:
258  test_info_part(kFlashInfoPageIdCreatorSecret, kRandomData1,
259  /*write_allowed=*/!personalized,
260  /*read_allowed=*/!personalized);
261  test_info_part(kFlashInfoPageIdOwnerSecret, kRandomData2,
262  /*write_allowed=*/1, /*read_allowed=*/1);
263  test_info_part(kFlashInfoPageIdIsoPart, kRandomData3, /*write_allowed=*/1,
264  /*read_allowed=*/1);
265  break;
266  case kDifLcCtrlStateRma:
267  test_info_part(kFlashInfoPageIdCreatorSecret, kRandomData1,
268  /*write_allowed=*/1, /*read_allowed=*/1);
269  test_info_part(kFlashInfoPageIdOwnerSecret, kRandomData2,
270  /*write_allowed=*/1, /*read_allowed=*/1);
271  test_info_part(kFlashInfoPageIdIsoPart, kRandomData3, /*write_allowed=*/1,
272  /*read_allowed=*/1);
273  break;
274  default:
275  LOG_ERROR("Unexpected lc state 0x%x", lc_state);
276  }
277  return true;
278 }