Software APIs
edn_sca.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 
6 #include "sw/device/lib/base/status.h"
7 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
10 #include "sw/device/lib/testing/rv_core_ibex_testutils.h"
11 #include "sw/device/lib/testing/test_framework/check.h"
12 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
13 #include "sw/device/lib/ujson/ujson.h"
14 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
15 #include "sw/device/tests/penetrationtests/json/edn_sca_commands.h"
16 
17 #include "edn_regs.h" // Generated
19 #include "rv_core_ibex_regs.h" // Generated
20 
21 // NOP macros.
22 #define NOP1 "addi x0, x0, 0\n"
23 #define NOP10 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1
24 #define NOP30 NOP10 NOP10 NOP10
25 
26 enum {
27  kEdnKatTimeout = (10 * 1000 * 1000),
28  kEdnKatMaxClen = 12,
29  kEdnKatOutputLen = 16,
30  kEdnKatWordsPerBlock = 4,
31  /**
32  * Max number of traces per batch.
33  */
34  kNumBatchOpsMax = 128,
35 };
36 
37 static dif_rv_core_ibex_t rv_core_ibex;
38 
39 /**
40  * Read randomness.
41  *
42  * The goal of this function is to allow the SCA setup to measure randomness
43  * transmitted from the 128-bit FIFO within the EDN to the Ibex RND_DATA
44  * register.
45  *
46  * To do so, this function first clears the 128-bit FIFO by reading it. When the
47  * FIFO is empty, the EDN sends a request to the CSRNG. When the FIFO again is
48  * full, set the SCA trigger and read the randomness from the FIFO to the
49  * RND_DATA register.
50  *
51  * @param ibex_rnd_data The array containing the randomness.
52  * @return OK or error.
53  */
54 static status_t read_rnd_data_reg(uint32_t ibex_rnd_data[4]) {
55  // Clear the CSRNG FIFO containing randomness before starting the test.
56  for (size_t it = 0; it < 4; it++) {
57  TRY(dif_rv_core_ibex_read_rnd_data(&rv_core_ibex, &ibex_rnd_data[0]));
58  }
59  memset(ibex_rnd_data, 0, 4 * sizeof(uint32_t));
60  // Wait until RND_DATA_VALID becomes true, i.e., randomness is available.
61  bool rnd_data_valid = rv_core_ibex_testutils_is_rnd_data_valid(&rv_core_ibex);
62  while (!rnd_data_valid) {
63  rnd_data_valid = rv_core_ibex_testutils_is_rnd_data_valid(&rv_core_ibex);
64  }
65 
66  // Read RND_DATA register. First access contains randomness that already was
67  // transmitted over the bus. Afterwards, data needs to be transmitted from the
68  // randomness FIFO into the RND_DATA register - this is what we want to
69  // measure.
70  pentest_set_trigger_high();
71  asm volatile(NOP30);
72  asm volatile("li t0, %0"
73  :
75  : "t0");
76  asm volatile("lw t1, %0(t0)"
77  :
78  : "i"(RV_CORE_IBEX_RND_DATA_REG_OFFSET)
79  : "t1");
80  asm volatile(NOP30);
81  asm volatile(NOP30);
82  pentest_set_trigger_low();
83  // Read RND_DATA which was transmitted from FIFO into RND_DATA register.
84  // Read it after the trigger window to not measure load into Ibex register
85  TRY(dif_rv_core_ibex_read_rnd_data(&rv_core_ibex, &ibex_rnd_data[3]));
86 
87  return OK_STATUS();
88 }
89 
90 status_t handle_edn_sca_bus_data_batch(ujson_t *uj) {
91  // Get number of iterations.
92  edn_sca_batch_t uj_data;
93  uint32_t max_iterations = 128;
94  TRY(ujson_deserialize_edn_sca_batch_t(uj, &uj_data));
95  CHECK(uj_data.num_iterations <= max_iterations);
96 
97  // Start num_iterations trigger windows.
98  uint32_t rand_data[max_iterations][4];
99  for (size_t it = 0; it < uj_data.num_iterations; it++) {
100  TRY(read_rnd_data_reg(rand_data[it]));
101  }
102 
103  // Send back num_iterations rand_data.
104  for (size_t it = 0; it < uj_data.num_iterations; it++) {
105  edn_sca_result_t uj_output;
106  memcpy(&uj_output.rnd_data, rand_data[it], 4 * sizeof(uint32_t));
107  RESP_OK(ujson_serialize_edn_sca_result_t, uj, &uj_output);
108  }
109 
110  return OK_STATUS();
111 }
112 
113 status_t handle_edn_sca_bus_data(ujson_t *uj) {
114  edn_sca_result_t uj_output;
115 
116  TRY(read_rnd_data_reg(uj_output.rnd_data));
117 
118  // Send data back to host.
119  RESP_OK(ujson_serialize_edn_sca_result_t, uj, &uj_output);
120  return OK_STATUS();
121 }
122 
123 status_t handle_edn_sca_init(ujson_t *uj) {
124  penetrationtest_cpuctrl_t uj_data;
125  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_data));
126 
127  pentest_select_trigger_type(kPentestTriggerTypeSw);
128  // As we are using the software defined trigger, the first argument of
129  // sca_init is not needed. kPentestTriggerSourceAes is selected as a
130  // placeholder.
131  pentest_init(kPentestTriggerSourceAes,
132  kPentestPeripheralIoDiv4 | kPentestPeripheralEntropy |
133  kPentestPeripheralCsrng | kPentestPeripheralEdn);
134 
135  // Disable the instruction cache and dummy instructions for SCA attacks.
136  penetrationtest_device_info_t uj_output;
137  TRY(pentest_configure_cpu(
138  uj_data.icache_disable, uj_data.dummy_instr_disable,
139  uj_data.enable_jittery_clock, uj_data.enable_sram_readback,
140  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
141  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
142  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
143 
144  // Configure Ibex to allow reading ERR_STATUS register.
145  TRY(dif_rv_core_ibex_init(
147  &rv_core_ibex));
148 
149  // Configure the entropy complex. Set the reseed interval to max to avoid
150  // reseed during the trigger window.
151  TRY(pentest_configure_entropy_source_max_reseed_interval());
152 
153  // Read device ID and return to host.
154  TRY(pentest_read_device_id(uj_output.device_id));
155  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
156 
157  return OK_STATUS();
158 }
159 
160 status_t handle_edn_sca(ujson_t *uj) {
161  edn_sca_subcommand_t cmd;
162  TRY(ujson_deserialize_edn_sca_subcommand_t(uj, &cmd));
163  switch (cmd) {
164  case kEdnScaSubcommandInit:
165  return handle_edn_sca_init(uj);
166  case kEdnScaSubcommandBusData:
167  return handle_edn_sca_bus_data(uj);
168  case kEdnScaSubcommandBusDataBatch:
169  return handle_edn_sca_bus_data_batch(uj);
170  default:
171  LOG_ERROR("Unrecognized EDN SCA subcommand: %d", cmd);
172  return INVALID_ARGUMENT();
173  }
174  return OK_STATUS();
175 }