Software APIs
lc_walkthrough_testunlocks_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/lc_ctrl_testutils.h"
12 #include "sw/device/lib/testing/otp_ctrl_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
14 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
15 
17 
18 #define LC_TOKEN_SIZE 16
19 
20 OTTF_DEFINE_TEST_CONFIG();
21 
22 static dif_lc_ctrl_t lc;
23 static dif_otp_ctrl_t otp;
24 static dif_rstmgr_t rstmgr;
25 
26 /**
27  * Track LC state transition tokens.
28  *
29  * These tokens will be further randomized and overridden by the testbench.
30  */
31 
32 // LC exit token value in OTP secret0 partition.
33 static volatile const uint8_t kOtpExitToken[LC_TOKEN_SIZE] = {
34  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
35  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
36 };
37 
38 // LC unlock token value in OTP secret0 partition.
39 static volatile const uint8_t kOtpUnlockToken[LC_TOKEN_SIZE] = {
40  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
41  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
42 };
43 
44 static void lock_otp_secret0_partition(void) {
45  uint64_t otp_unlock_token_0 = 0;
46  uint64_t otp_unlock_token_1 = 0;
47  for (int i = 0; i < LC_TOKEN_SIZE; i++) {
48  if (i < LC_TOKEN_SIZE / 2) {
49  otp_unlock_token_0 |= (uint64_t)kOtpUnlockToken[i] << (i * 8);
50  } else {
51  otp_unlock_token_1 |= (uint64_t)kOtpUnlockToken[i]
52  << ((i - LC_TOKEN_SIZE / 2) * 8);
53  }
54  }
55 
56  uint64_t otp_exit_token_0 = 0;
57  uint64_t otp_exit_token_1 = 0;
58  for (int i = 0; i < LC_TOKEN_SIZE; i++) {
59  if (i < LC_TOKEN_SIZE / 2) {
60  otp_exit_token_0 |= (uint64_t)kOtpExitToken[i] << (i * 8);
61  } else {
62  otp_exit_token_1 |= (uint64_t)kOtpExitToken[i]
63  << ((i - LC_TOKEN_SIZE / 2) * 8);
64  }
65  }
66 
68  /*address=*/0x0,
69  /*value=*/otp_unlock_token_0));
70  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp));
72  /*address=*/0x8,
73  /*value=*/otp_unlock_token_1));
74  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp));
76  /*address=*/0x10,
77  /*value=*/otp_exit_token_0));
78  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp));
80  /*address=*/0x18,
81  /*value=*/otp_exit_token_1));
82  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp));
83 
85  /*digest=*/0));
86  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp));
87 }
88 
89 static void get_dest_state_and_cnt(dif_lc_ctrl_state_t *curr_state,
90  dif_lc_ctrl_state_t *dest_state,
91  uint8_t *exp_cnt) {
92  switch (*curr_state) {
94  *dest_state = kDifLcCtrlStateTestLocked0;
95  *exp_cnt = 1;
96  break;
98  *dest_state = kDifLcCtrlStateTestLocked1;
99  *exp_cnt = 3;
100  break;
102  *dest_state = kDifLcCtrlStateTestLocked2;
103  *exp_cnt = 5;
104  break;
106  *dest_state = kDifLcCtrlStateTestLocked3;
107  *exp_cnt = 7;
108  break;
110  *dest_state = kDifLcCtrlStateTestLocked4;
111  *exp_cnt = 9;
112  break;
114  *dest_state = kDifLcCtrlStateTestLocked5;
115  *exp_cnt = 11;
116  break;
118  *dest_state = kDifLcCtrlStateTestLocked6;
119  *exp_cnt = 13;
120  break;
122  *dest_state = kDifLcCtrlStateRaw;
123  *exp_cnt = 15;
124  break;
125  default:
126  LOG_FATAL("Unexpected state = %d", curr_state);
127  abort();
128  }
129 }
130 
131 /**
132  * Walkthrough LC all TestUnlock and TestLock states.
133  *
134  * 1). Preload OTP RAW image file.
135  * 2). DV sequence drives JTAG interface to write RawUnlockToken and
136  * transfers LC state to TestUnlock0 state.
137  * 3). In TestUnlock0 state, SW programs OTP secret0 partition to write
138  * ExitToken and TestUnlockToken.
139  * 4). DV sequence issues reset to lock OTP secret0 partition.
140  * 5). SW requests a LC state transfer to TestLock0 state with all zero tokens.
141  * 6). DV sequence issues reset and SW check if LC transfers to the destination
142  * state.
143  * 7). DV sequence requests a LC state transfer to TestUnlock1 state with test
144  * unlock tokens.
145  * Repeat the above transition until reaches the last TestUnlock state.
146  *
147  */
148 
149 bool test_main(void) {
150  LOG_INFO("Start LC walkthrough testunlocks test.");
151 
152  mmio_region_t lc_reg =
154  CHECK_DIF_OK(dif_lc_ctrl_init(lc_reg, &lc));
155 
156  mmio_region_t otp_reg =
158  CHECK_DIF_OK(dif_otp_ctrl_init(otp_reg, &otp));
159 
160  CHECK_DIF_OK(dif_rstmgr_init(
162 
163  LOG_INFO("Read and check LC state and count.");
164  dif_lc_ctrl_state_t curr_state;
165  CHECK_DIF_OK(dif_lc_ctrl_get_state(&lc, &curr_state));
166 
167  dif_lc_ctrl_state_t kDestState;
168  uint8_t kExpCnt;
169  get_dest_state_and_cnt(&curr_state, &kDestState, &kExpCnt);
170 
171  CHECK_STATUS_OK(lc_ctrl_testutils_check_transition_count(&lc, kExpCnt));
172 
173  bool secret0_locked;
174  CHECK_DIF_OK(dif_otp_ctrl_is_digest_computed(
175  &otp, kDifOtpCtrlPartitionSecret0, &secret0_locked));
176  if (!secret0_locked) {
177  // Write LC tokens to OTP secret0 partition.
178  lock_otp_secret0_partition();
179  LOG_INFO("Wrote and locked OTP secret0 partition!");
180  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
182  // Unreachable
183  return false;
184  }
185 
186  if (kDestState != kDifLcCtrlStateRaw) {
187  // Issue a LC state transfer to destination state.
188  dif_lc_ctrl_token_t token;
189  for (int i = 0; i < LC_TOKEN_SIZE; i++) {
190  // Transition from TestUnlock to TestLock state is unconditional and
191  // requires to write all zero default tokens.
192  token.data[i] = 0;
193  }
194 
195  CHECK_DIF_OK(dif_lc_ctrl_mutex_try_acquire(&lc));
196 
197  // TODO(lowRISC/opentitan#12775): randomize using external or internal
198  // clock.
199  bool use_ext_clock = false;
200  CHECK_DIF_OK(dif_lc_ctrl_configure(&lc, kDestState, use_ext_clock, &token),
201  "LC transition configuration failed!");
202  CHECK_DIF_OK(dif_lc_ctrl_transition(&lc), "LC transition failed!");
203 
204  LOG_INFO("Waiting for LC transtition %d done and reboot.", kDestState);
206 
207  // Unreachable.
208  return false;
209  } else {
210  // Reached TestUnlock7 state, exit SW test.
211  return true;
212  }
213 }