Software APIs
csrng_lc_hw_debug_en_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 
15 #include "sw/device/lib/testing/csrng_testutils.h"
16 #include "sw/device/lib/testing/entropy_src_testutils.h"
17 #include "sw/device/lib/testing/entropy_testutils.h"
18 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
19 #include "sw/device/lib/testing/otp_ctrl_testutils.h"
20 #include "sw/device/lib/testing/rand_testutils.h"
21 #include "sw/device/lib/testing/rstmgr_testutils.h"
22 #include "sw/device/lib/testing/test_framework/check.h"
24 
26 
27 OTTF_DEFINE_TEST_CONFIG();
28 
29 enum {
30  /**
31  * The size of the buffer used in firmware to process the entropy bits in
32  * firmware override mode.
33  */
34  kEntropyFifoBufferSize = 12,
35  /**
36  * Maximum number of attempts of entropy_src operations that may stall due
37  * to FIFO operations.
38  */
39  kTestParamEntropySrcMaxAttempts = 256,
40  /**
41  * The size of the exit token in bytes or words.
42  */
43  kExitTokenSizeInBytes = 16,
44  kExitTokenSizeInWords = kExitTokenSizeInBytes / sizeof(uint32_t),
45 };
46 
47 // Store CSRNG output in flash to compare results across life cycle stages.
48 OT_SET_BSS_SECTION(".non_volatile_scratch",
49  uint32_t nv_csrng_output[kEntropyFifoBufferSize];)
50 
51 static dif_lc_ctrl_t lc_ctrl;
52 static dif_otp_ctrl_t otp_ctrl;
53 static dif_csrng_t csrng;
54 static dif_entropy_src_t entropy_src;
55 static dif_flash_ctrl_state_t flash_ctrl_state;
56 static dif_kmac_t kmac;
57 static dif_rstmgr_t rstmgr;
58 
59 // LC exit token value for LC state transition.
60 static const dif_lc_ctrl_token_t kLcExitToken = {
61  .data =
62  {
63  0x00,
64  0x01,
65  0x02,
66  0x03,
67  0x04,
68  0x05,
69  0x06,
70  0x07,
71  0x08,
72  0x09,
73  0x0a,
74  0x0b,
75  0x0c,
76  0x0d,
77  0x0e,
78  0x0f,
79  },
80 };
81 static_assert(kExitTokenSizeInBytes == ARRAYSIZE(kLcExitToken.data),
82  "Invalid exit token size.");
83 
84 /**
85  * Initializes KMAC with software provided entropy to avoid sending requests to
86  * EDN0.
87  */
88 static void kmac_init(void) {
89  CHECK_DIF_OK(
90  dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
91 
92  // Configure KMAC hardware using software entropy.
94  .entropy_mode = kDifKmacEntropyModeSoftware,
95  .entropy_seed = {0xb153e3fe, 0x09596819, 0x3e85a6e8, 0xb6dcdaba,
96  0x50dc409c, 0x11e1ebd1},
97  .entropy_fast_process = kDifToggleEnabled,
98  };
99  CHECK_DIF_OK(dif_kmac_configure(&kmac, config));
100 }
101 
102 /**
103  * Initializes the peripherals used in this test.
104  */
105 static void peripherals_init(void) {
106  CHECK_DIF_OK(dif_csrng_init(
108  CHECK_DIF_OK(dif_lc_ctrl_init(
110  CHECK_DIF_OK(dif_entropy_src_init(
112  CHECK_DIF_OK(dif_otp_ctrl_init(
114  CHECK_DIF_OK(dif_rstmgr_init(
116 
117  CHECK_DIF_OK(dif_flash_ctrl_init_state(
118  &flash_ctrl_state,
120 
121  kmac_init();
122 }
123 
124 /**
125  * Calculates the cShake128 of the test exit token and returns its
126  * representation in two 64bit halves.
127  *
128  * @param[out] otp_token_l Lower half of the text exit token.
129  * @param[out] otp_token_h Higher half of the text exit token.
130  */
131 static void exit_token_cshake_hash(uint64_t *otp_token_l,
132  uint64_t *otp_token_h) {
134  CHECK_DIF_OK(
135  dif_kmac_customization_string_init(/*data=*/"LC_CTRL", /*len=*/7, &s));
136 
138  CHECK_DIF_OK(dif_kmac_mode_cshake_start(
139  &kmac, &op_state, kDifKmacModeCshakeLen128, /*n=*/NULL, &s));
140  CHECK_DIF_OK(dif_kmac_absorb(&kmac, &op_state, kLcExitToken.data,
141  ARRAYSIZE(kLcExitToken.data),
142  /*processed=*/NULL));
143 
144  uint32_t token_hash[kExitTokenSizeInWords];
145  CHECK_DIF_OK(dif_kmac_squeeze(&kmac, &op_state, token_hash,
146  kExitTokenSizeInWords, /*processed=*/NULL,
147  /*capacity=*/NULL));
148  CHECK_DIF_OK(dif_kmac_end(&kmac, &op_state));
149 
150  *otp_token_l = 0;
151  *otp_token_h = 0;
152  uint8_t *p_token = (uint8_t *)token_hash;
153  for (size_t i = 0; i < kExitTokenSizeInBytes; i++) {
154  if (i < kExitTokenSizeInBytes / 2) {
155  *otp_token_l |= (uint64_t)p_token[i] << (i * 8);
156  } else {
157  *otp_token_h |= (uint64_t)p_token[i]
158  << ((i - kExitTokenSizeInBytes / 2) * 8);
159  }
160  }
161 }
162 
163 /**
164  * Configures the test exit token and locks down the secret0 partition.
165  */
166 static void lock_otp_secret0_partition(void) {
167  uint64_t otp_token_l;
168  uint64_t opt_token_h;
169  exit_token_cshake_hash(&otp_token_l, &opt_token_h);
170 
171  CHECK_DIF_OK(dif_otp_ctrl_dai_program64(&otp_ctrl,
173  /*address=*/0x10,
174  /*value=*/otp_token_l));
175  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp_ctrl));
176  CHECK_DIF_OK(dif_otp_ctrl_dai_program64(&otp_ctrl,
178  /*address=*/0x18,
179  /*value=*/opt_token_h));
180  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp_ctrl));
181 
183  /*digest=*/0));
184  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp_ctrl));
185 }
186 
187 /**
188  * Retuns a random pick one DEV, PROD or PROD_END lc state.
189  */
190 static dif_lc_ctrl_state_t lc_next_state(void) {
191  uint32_t index = rand_testutils_gen32_range(/*min=*/0, /*max=*/2);
192  dif_lc_ctrl_state_t next_state;
193  switch (index) {
194  case 0:
195  next_state = kDifLcCtrlStateDev;
196  break;
197  case 1:
198  next_state = kDifLcCtrlStateProd;
199  break;
200  case 2:
201  next_state = kDifLcCtrlStateProdEnd;
202  break;
203  default:
204  CHECK(false, "Unexpected case index: %d", index);
205  return kDifLcCtrlStateInvalid;
206  }
207  return next_state;
208 }
209 
210 /**
211  * Stops the entropy_src conditioner.
212  *
213  * @param entropy_src A entropy source handle.
214  */
215 static void entropy_conditioner_stop(const dif_entropy_src_t *entropy_src) {
216  uint32_t fail_count = 0;
217  dif_result_t op_result;
218  do {
219  op_result = dif_entropy_src_conditioner_stop(entropy_src);
220  if (op_result == kDifIpFifoFull) {
221  CHECK(fail_count++ < kTestParamEntropySrcMaxAttempts);
222  } else {
223  CHECK_DIF_OK(op_result);
224  }
225  } while (op_result == kDifIpFifoFull);
226 }
227 
228 /**
229  * Writes data to the entropy source firmware override buffer.
230  *
231  * @param entropy_src A entropy source handle.
232  */
233 static void fw_override_conditioner_write(
234  const dif_entropy_src_t *entropy_src) {
235  CHECK_DIF_OK(dif_entropy_src_conditioner_start(entropy_src));
236 
237  const uint32_t kInputMsg[kEntropyFifoBufferSize] = {
238  0xa52a0da9, 0xcae141b2, 0x6d5bab9d, 0x2c3e5cc0, 0x225afc93, 0x5d31a610,
239  0x91b7f960, 0x0d566bb3, 0xef35e170, 0x94ba7d8e, 0x534eb741, 0x6b60b0da,
240  };
241 
242  uint32_t fail_count = 0;
243  uint32_t total = 0;
244  do {
245  uint32_t count;
247  entropy_src, kInputMsg + total, ARRAYSIZE(kInputMsg) - total, &count);
248  total += count;
249  if (op_result == kDifIpFifoFull) {
250  CHECK(fail_count++ < kTestParamEntropySrcMaxAttempts);
251  } else {
252  fail_count = 0;
253  CHECK_DIF_OK(op_result);
254  }
255  } while (total < ARRAYSIZE(kInputMsg));
256  entropy_conditioner_stop(entropy_src);
257 }
258 
259 /**
260  * Issues CSRNG instantiate and generate command.
261  *
262  * @param[out] output Output buffer.
263  * @param output_len Requested number of entropy words. It must be at least the
264  * size of the `output` buffer.
265  */
266 static void csrng_static_generate_run(uint32_t *output, size_t output_len) {
267  CHECK_STATUS_OK(entropy_testutils_stop_all());
268  // TODO: May need to flush the output buffers before enabling enabling
269  // firmware override connected to csrng.
270  CHECK_STATUS_OK(entropy_src_testutils_fw_override_enable(
271  &entropy_src, kEntropyFifoBufferSize,
272  /*firmware_override_enable=*/false,
273  /*bypass_conditioner=*/false));
274  CHECK_DIF_OK(dif_csrng_configure(&csrng));
275  fw_override_conditioner_write(&entropy_src);
276 
277  const dif_csrng_seed_material_t kEmptySeedMaterial = {0};
279  &kEmptySeedMaterial));
280 
281  CHECK_STATUS_OK(csrng_testutils_cmd_generate_run(&csrng, output, output_len));
282  uint32_t prev_word = 0;
283  for (size_t i = 0; i < output_len; ++i) {
284  CHECK(prev_word != output[i],
285  "Unexpected duplicate value at index: %d value: 0x%x", i, prev_word);
286  prev_word = output[i];
287  }
288 }
289 
290 bool test_main(void) {
291  peripherals_init();
292  CHECK_STATUS_OK(
293  flash_ctrl_testutils_default_region_access(&flash_ctrl_state,
294  /*rd_en=*/true,
295  /*prog_en=*/true,
296  /*erase_en=*/true,
297  /*scramble_en=*/false,
298  /*ecc_en=*/false,
299  /*he_en=*/false));
300 
301  dif_rstmgr_reset_info_bitfield_t rst_info = rstmgr_testutils_reason_get();
302  rstmgr_testutils_reason_clear();
303 
304  dif_lc_ctrl_state_t lc_state;
305  CHECK_DIF_OK(dif_lc_ctrl_get_state(&lc_ctrl, &lc_state));
306  LOG_INFO("lc state: %d", lc_state);
307 
308  if (rst_info == kDifRstmgrResetInfoPor &&
309  lc_state == kDifLcCtrlStateTestUnlocked0) {
310  enum {
311  kPartitionId = 0,
312  };
313  uint32_t address =
314  (uint32_t)(nv_csrng_output)-TOP_EARLGREY_FLASH_CTRL_MEM_BASE_ADDR;
315  uint32_t expected[kEntropyFifoBufferSize];
316  csrng_static_generate_run(expected, ARRAYSIZE(expected));
317  CHECK_STATUS_OK(flash_ctrl_testutils_write(&flash_ctrl_state, address,
318  /*partition_id=*/0, expected,
319  kDifFlashCtrlPartitionTypeData,
320  ARRAYSIZE(expected)));
321  CHECK_ARRAYS_EQ(nv_csrng_output, expected, ARRAYSIZE(expected));
322 
323  lock_otp_secret0_partition();
324  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
325 
326  // The CPU may be able to continue execution before the reset takes effect.
328  CHECK(false, "Unexpected wakeup.");
329  } else if (rst_info == kDifRstmgrResetInfoSw &&
330  lc_state == kDifLcCtrlStateTestUnlocked0) {
331  uint32_t got[kEntropyFifoBufferSize];
332  csrng_static_generate_run(got, ARRAYSIZE(got));
333  static_assert(ARRAYSIZE(got) == ARRAYSIZE(nv_csrng_output),
334  "Array size mismatch.");
335  CHECK_ARRAYS_EQ(got, nv_csrng_output, ARRAYSIZE(got));
336 
337  CHECK_DIF_OK(dif_lc_ctrl_mutex_try_acquire(&lc_ctrl));
338  CHECK_DIF_OK(dif_lc_ctrl_configure(&lc_ctrl, lc_next_state(),
339  /*use_ext_clock=*/false, &kLcExitToken),
340  "LC transition configuration failed!");
341 
342  CHECK_DIF_OK(dif_lc_ctrl_transition(&lc_ctrl), "LC transition failed!");
343 
344  // SV testbench waits for this message.
345  LOG_INFO("LC transition in progress.");
347  CHECK(false, "Unexpected wakeup.");
348  } else {
349  CHECK(lc_state == kDifLcCtrlStateDev || lc_state == kDifLcCtrlStateProd ||
350  lc_state == kDifLcCtrlStateProdEnd,
351  "Unexpected LC state: %d", lc_state);
352  uint32_t got[kEntropyFifoBufferSize];
353  csrng_static_generate_run(got, ARRAYSIZE(got));
354  static_assert(ARRAYSIZE(got) == ARRAYSIZE(nv_csrng_output),
355  "Array size mismatch.");
356 
357  if (lc_state == kDifLcCtrlStateDev) {
358  CHECK_ARRAYS_EQ(got, nv_csrng_output, ARRAYSIZE(got));
359  } else {
360  CHECK_ARRAYS_NE(got, nv_csrng_output, ARRAYSIZE(got));
361  }
362  return true;
363  }
364  CHECK(false, "Invalid reset: %d, or LC state: %d", rst_info, lc_state);
365  return false;
366 }