Software APIs
ibex_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 
5 #include "sw/device/tests/penetrationtests/firmware/sca/ibex_sca.h"
6 
8 #include "sw/device/lib/base/status.h"
12 #include "sw/device/lib/testing/keymgr_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 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
16 #include "sw/device/lib/ujson/ujson.h"
17 #include "sw/device/sca/lib/prng.h"
18 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
19 #include "sw/device/tests/penetrationtests/json/ibex_sca_commands.h"
20 
22 
23 static dif_keymgr_t keymgr;
24 static dif_kmac_t kmac;
25 
26 #define MAX_BATCH_SIZE 256
27 #define DEST_REGS_CNT 6
28 
29 // Indicates whether the key manager is already configured for the test.
30 static bool key_manager_init;
31 
32 // Buffer to allow the compiler to allocate a safe area in Main SRAM where
33 // we can do the write/read test without the risk of clobbering data
34 // used by the program.
35 OT_SECTION(".data")
36 static volatile uint32_t sram_main_buffer[8];
37 static volatile uint32_t sram_main_buffer_batch[256];
38 
39 // Load value in x5. Zeroize x6...x7 and x28...x31.
40 static inline void init_registers(uint32_t val0, uint32_t val1, uint32_t val2,
41  uint32_t val3, uint32_t val4, uint32_t val5) {
42  asm volatile("mv x5, %0" : : "r"(val0) : "x5");
43  asm volatile("mv x18, %0" : : "r"(val1) : "x18");
44  asm volatile("mv x19, %0" : : "r"(val2) : "x19");
45  asm volatile("mv x20, %0" : : "r"(val3) : "x20");
46  asm volatile("mv x21, %0" : : "r"(val4) : "x21");
47  asm volatile("mv x22, %0" : : "r"(val5) : "x22");
48  asm volatile("mv x6, x0" : : : "x6");
49  asm volatile("mv x7, x0" : : : "x7");
50  asm volatile("mv x28, x0" : : : "x28");
51  asm volatile("mv x29, x0" : : : "x29");
52  asm volatile("mv x30, x0" : : : "x30");
53  asm volatile("mv x31, x0" : : : "x31");
54 }
55 
56 // Function to assign x6...x7 and x28...x31 the provided values val0...val6.
57 // Inline to avoid function calls for SCA measurements.
58 static inline void move_bw_registers(void) {
59  asm volatile("mv x6, x5" : : : "x6");
60  asm volatile("mv x7, x18" : : : "x7");
61  asm volatile("mv x28, x19" : : : "x28");
62  asm volatile("mv x29, x20" : : : "x29");
63  asm volatile("mv x30, x21" : : : "x30");
64  asm volatile("mv x31, x22" : : : "x31");
65 }
66 
67 // Function to assign x5...x7 and x28...x31 the provided values val0...val6.
68 // Inline to avoid function calls for SCA measurements.
69 static inline void copy_to_registers(uint32_t val0, uint32_t val1,
70  uint32_t val2, uint32_t val3,
71  uint32_t val4, uint32_t val5,
72  uint32_t val6) {
73  asm volatile("mv x5, %0" : : "r"(val0) : "x5");
74  asm volatile("mv x6, %0" : : "r"(val1) : "x6");
75  asm volatile("mv x7, %0" : : "r"(val2) : "x7");
76  asm volatile("mv x28, %0" : : "r"(val3) : "x28");
77  asm volatile("mv x29, %0" : : "r"(val4) : "x29");
78  asm volatile("mv x30, %0" : : "r"(val5) : "x30");
79  asm volatile("mv x31, %0" : : "r"(val6) : "x31");
80 }
81 
82 // Generate Fixed vs Random (FvsR) array of values. The fixed value is provided
83 // by the user and the random values are generated by the PRNG provided in the
84 // SCA library.
85 static void generate_fvsr(size_t num_iterations, uint32_t fixed_data,
86  uint32_t values[]) {
87  bool sample_fixed = true;
88  for (size_t i = 0; i < num_iterations; i++) {
89  if (sample_fixed) {
90  values[i] = fixed_data;
91  } else {
92  values[i] = prng_rand_uint32();
93  }
94  sample_fixed = prng_rand_uint32() & 0x1;
95  }
96 }
97 
98 // Generate random values used by the test by calling the SCA PRNG.
99 static void generate_random(size_t num_iterations, uint32_t values[]) {
100  for (size_t i = 0; i < num_iterations; i++) {
101  values[i] = prng_rand_uint32();
102  }
103 }
104 
105 status_t handle_ibex_pentest_init(ujson_t *uj) {
106  penetrationtest_cpuctrl_t uj_data;
107  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_data));
108 
109  // Setup trigger and enable peripherals needed for the test.
110  pentest_select_trigger_type(kPentestTriggerTypeSw);
111  // As we are using the software defined trigger, the first argument of
112  // pentest_init is not needed. kPentestTriggerSourceAes is selected as a
113  // placeholder.
114  pentest_init(kPentestTriggerSourceAes,
115  kPentestPeripheralIoDiv4 | kPentestPeripheralKmac);
116 
117  // Disable the instruction cache and dummy instructions for SCA.
118  penetrationtest_device_info_t uj_output;
119  TRY(pentest_configure_cpu(
120  uj_data.icache_disable, uj_data.dummy_instr_disable,
121  uj_data.enable_jittery_clock, uj_data.enable_sram_readback,
122  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
123  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
124  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
125 
126  // Key manager not initialized for the handle_ibex_sca_key_sideloading test.
127  key_manager_init = false;
128 
129  // Read device ID and return to host.
130  TRY(pentest_read_device_id(uj_output.device_id));
131  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
132 
133  return OK_STATUS();
134 }
135 
136 status_t handle_ibex_sca_key_sideloading(ujson_t *uj) {
137  ibex_sca_salt_t uj_data;
138  TRY(ujson_deserialize_ibex_sca_salt_t(uj, &uj_data));
139 
140  if (!key_manager_init) {
141  // Initialize keymgr and advance to CreatorRootKey state.
142  TRY(keymgr_testutils_startup(&keymgr, &kmac));
143 
144  // Generate identity at CreatorRootKey (to follow same sequence and reuse
145  // chip_sw_keymgr_key_derivation_vseq.sv).
146  TRY(keymgr_testutils_generate_identity(
147  &keymgr,
149 
150  // Advance to OwnerIntermediateKey state.
151  TRY(keymgr_testutils_advance_state(&keymgr, &kOwnerIntParams));
152  TRY(keymgr_testutils_check_state(&keymgr,
154  key_manager_init = true;
155  }
156 
157  // Set the salt based on the input.
158  dif_keymgr_versioned_key_params_t sideload_params = kKeyVersionedParams;
159  for (int i = 0; i < 8; i++) {
160  sideload_params.salt[i] = uj_data.salt[i];
161  }
162 
163  // Trigger keymanager to create a new key based on the provided salt.
164  pentest_set_trigger_high();
165  TRY(keymgr_testutils_generate_versioned_key(&keymgr, sideload_params));
166  pentest_set_trigger_low();
167 
168  // Read back generated key provided at the software interface.
170  TRY(dif_keymgr_read_output(&keymgr, &key));
171 
172  // Acknowledge test.
173  ibex_sca_key_t uj_key;
174  for (int i = 0; i < 8; i++) {
175  uj_key.share0[i] = key.value[0][i];
176  uj_key.share1[i] = key.value[1][i];
177  }
178  RESP_OK(ujson_serialize_ibex_sca_key_t, uj, &uj_key);
179  return OK_STATUS();
180 }
181 
182 status_t handle_ibex_sca_register_file_read(ujson_t *uj) {
183  // Get data to write into RF.
184  ibex_sca_test_data_t uj_data;
185  TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data));
186  // Initialize temporary registers with reference values.
187  copy_to_registers(uj_data.data[0], uj_data.data[1], uj_data.data[2],
188  uj_data.data[3], uj_data.data[4], uj_data.data[5], 0);
189 
190  // SCA code target.
191  pentest_set_trigger_high();
192  // Give the trigger time to rise.
193  asm volatile(NOP30);
194  // Copy registers.
195  asm volatile("mv x28, x5");
196  asm volatile("mv x29, x6");
197  asm volatile("mv x30, x7");
198  pentest_set_trigger_low();
199 
200  // Acknowledge test.
201  ibex_sca_result_t uj_output;
202  uj_output.result = 0;
203  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
204  return OK_STATUS();
205 }
206 
207 status_t handle_ibex_sca_register_file_read_batch_fvsr(ujson_t *uj) {
208  // Get number of iterations and fixed data.
209  ibex_sca_test_fvsr_t uj_data;
210  TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data));
211  TRY_CHECK(uj_data.num_iterations < 256);
212 
213  // Generate FvsR values.
214  uint32_t values[256];
215  generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values);
216 
217  for (size_t i = 0; i < uj_data.num_iterations; i++) {
218  // Initialize temporary registers with reference values.
219  copy_to_registers(0, 0, 0, values[i], values[i], values[i], values[i]);
220  asm volatile(NOP30);
221  // SCA code target.
222  pentest_set_trigger_high();
223  // Give the trigger time to rise.
224  asm volatile(NOP30);
225  // Copy registers.
226  asm volatile("mv x5, x28");
227  asm volatile("mv x6, x29");
228  asm volatile("mv x7, x30");
229  pentest_set_trigger_low();
230  }
231 
232  // Write back last value written into the RF to validate generated data.
233  ibex_sca_result_t uj_output;
234  uj_output.result = values[uj_data.num_iterations - 1];
235  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
236  return OK_STATUS();
237 }
238 
239 status_t handle_ibex_sca_register_file_read_batch_random(ujson_t *uj) {
240  // Get number of iterations.
241  ibex_sca_batch_t uj_data;
242  TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data));
243  TRY_CHECK(uj_data.num_iterations < 256);
244 
245  // Generate random values.
246  uint32_t values[256];
247  generate_random(uj_data.num_iterations, values);
248 
249  for (size_t i = 0; i < uj_data.num_iterations; i++) {
250  // Initialize temporary registers with reference values.
251  copy_to_registers(0, 0, 0, values[i], values[i], values[i], values[i]);
252  asm volatile(NOP30);
253  // SCA code target.
254  pentest_set_trigger_high();
255  // Give the trigger time to rise.
256  asm volatile(NOP30);
257  // Copy registers.
258  asm volatile("mv x5, x28");
259  asm volatile("mv x6, x29");
260  asm volatile("mv x7, x30");
261  pentest_set_trigger_low();
262  }
263 
264  // Write back last value written into the RF to validate generated data.
265  ibex_sca_result_t uj_output;
266  uj_output.result = values[uj_data.num_iterations - 1];
267  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
268  return OK_STATUS();
269 }
270 
271 status_t handle_ibex_sca_register_file_write(ujson_t *uj) {
272  // Get data to write into RF.
273  ibex_sca_test_data_t uj_data;
274  TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data));
275 
276  // SCA code target.
277  pentest_set_trigger_high();
278  // Give the trigger time to rise.
279  asm volatile(NOP30);
280  // Write provided data into register file.
281  copy_to_registers(uj_data.data[0], uj_data.data[1], uj_data.data[2],
282  uj_data.data[3], uj_data.data[4], uj_data.data[5],
283  uj_data.data[6]);
284  pentest_set_trigger_low();
285 
286  // Acknowledge test.
287  ibex_sca_result_t uj_output;
288  uj_output.result = 0;
289  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
290  return OK_STATUS();
291 }
292 
293 status_t handle_ibex_sca_register_file_write_batch_fvsr(ujson_t *uj) {
294  // Get number of iterations and fixed data.
295  ibex_sca_test_fvsr_t uj_data;
296  TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data));
297  TRY_CHECK(uj_data.num_iterations < MAX_BATCH_SIZE);
298 
299  // Generate FvsR values.
300  uint32_t values[MAX_BATCH_SIZE];
301  generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values);
302 
303  // SCA code target.
304  for (size_t i = 0; i < uj_data.num_iterations; i++) {
305  pentest_set_trigger_high();
306  init_registers(values[i], values[i], values[i], values[i], values[i],
307  values[i]);
308  // Give the trigger time to rise.
309  asm volatile(NOP10);
310  // Write provided data into register file.
311  move_bw_registers();
312  pentest_set_trigger_low();
313  asm volatile(NOP30);
314  }
315 
316  // Write back last value written into the RF to validate generated data.
317  ibex_sca_result_t uj_output;
318  uj_output.result = values[uj_data.num_iterations - 1];
319  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
320  return OK_STATUS();
321 }
322 
323 status_t handle_ibex_sca_register_file_write_batch_random(ujson_t *uj) {
324  // Get number of iterations.
325  ibex_sca_batch_t uj_data;
326  TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data));
327  TRY_CHECK(uj_data.num_iterations < MAX_BATCH_SIZE);
328 
329  // Generate random values.
330  uint32_t values[MAX_BATCH_SIZE * DEST_REGS_CNT];
331  generate_random(uj_data.num_iterations * DEST_REGS_CNT, values);
332 
333  // SCA code target.
334  for (size_t i = 0; i < uj_data.num_iterations; i++) {
335  pentest_set_trigger_high();
336  init_registers(values[i * DEST_REGS_CNT], values[i * DEST_REGS_CNT + 1],
337  values[i * DEST_REGS_CNT + 2], values[i * DEST_REGS_CNT + 3],
338  values[i * DEST_REGS_CNT + 4],
339  values[i * DEST_REGS_CNT + 5]);
340  // Give the trigger time to rise.
341  asm volatile(NOP10);
342  // Write provided data into register file.
343  move_bw_registers();
344  pentest_set_trigger_low();
345  asm volatile(NOP30);
346  }
347 
348  // Write back last value written into the RF to validate generated data.
349  ibex_sca_result_t uj_output;
350  uj_output.result = values[uj_data.num_iterations * DEST_REGS_CNT - 1];
351  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
352  return OK_STATUS();
353 }
354 
355 status_t handle_ibex_sca_tl_read(ujson_t *uj) {
356  // Get data to write into SRAM.
357  ibex_sca_test_data_t uj_data;
358  TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data));
359 
360  // Get address of buffer located in SRAM.
361  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer;
362  mmio_region_t sram_region_main_addr =
363  mmio_region_from_addr(sram_main_buffer_addr);
364 
365  // Write provided data into SRAM.
366  for (int i = 0; i < 8; i++) {
367  mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t),
368  uj_data.data[i]);
369  }
370 
371  uint32_t read_data[8];
372 
373  // SCA code target.
374  pentest_set_trigger_high();
375  // Give the trigger time to rise.
376  asm volatile(NOP30);
377  // Fetch data from SRAM.
378  for (int i = 0; i < 8; i++) {
379  read_data[i] = mmio_region_read32(sram_region_main_addr,
380  i * (ptrdiff_t)sizeof(uint32_t));
381  }
382  pentest_set_trigger_low();
383  // Acknowledge test.
384  ibex_sca_result_t uj_output;
385  uj_output.result = 0;
386  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
387  return OK_STATUS();
388 }
389 
390 status_t handle_ibex_sca_tl_read_batch_fvsr(ujson_t *uj) {
391  // Get number of iterations and fixed data.
392  ibex_sca_test_fvsr_t uj_data;
393  TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data));
394  TRY_CHECK(uj_data.num_iterations < 256);
395 
396  // Generate FvsR values.
397  uint32_t values[256];
398  generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values);
399 
400  // Get address of buffer located in SRAM.
401  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch;
402  mmio_region_t sram_region_main_addr =
403  mmio_region_from_addr(sram_main_buffer_addr);
404 
405  // Write provided data into SRAM.
406  for (int i = 0; i < uj_data.num_iterations; i++) {
407  mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t),
408  values[i]);
409  }
410 
411  uint32_t read_data[256];
412 
413  // SCA code target.
414  // Fetch data from SRAM.
415  for (int i = 0; i < uj_data.num_iterations; i++) {
416  pentest_set_trigger_high();
417  // Give the trigger time to rise.
418  asm volatile(NOP30);
419  read_data[i] = mmio_region_read32(sram_region_main_addr,
420  i * (ptrdiff_t)sizeof(uint32_t));
421  pentest_set_trigger_low();
422  asm volatile(NOP30);
423  }
424 
425  // Write back last value read from SRAM to validate generated data.
426  ibex_sca_result_t uj_output;
427  uj_output.result = read_data[uj_data.num_iterations - 1];
428  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
429  return OK_STATUS();
430 }
431 
432 status_t handle_ibex_sca_tl_read_batch_fvsr_fix_address(ujson_t *uj) {
433  // Get number of iterations and fixed data.
434  ibex_sca_test_fvsr_t uj_data;
435  TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data));
436  TRY_CHECK(uj_data.num_iterations < 256);
437 
438  // Generate FvsR values.
439  uint32_t values[256];
440  generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values);
441 
442  // Get address of buffer located in SRAM.
443  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch;
444  mmio_region_t sram_region_main_addr =
445  mmio_region_from_addr(sram_main_buffer_addr);
446 
447  uint32_t read_data[256];
448 
449  // SCA code target.
450  // Fetch data from SRAM.
451  for (size_t i = 0; i < uj_data.num_iterations; i++) {
452  mmio_region_write32(sram_region_main_addr, 0, values[i]);
453  asm volatile(NOP30);
454  pentest_set_trigger_high();
455  // Give the trigger time to rise.
456  asm volatile(NOP30);
457  read_data[i] = mmio_region_read32(sram_region_main_addr, 0);
458  pentest_set_trigger_low();
459  }
460 
461  // Write back last value read from SRAM to validate generated data.
462  ibex_sca_result_t uj_output;
463  uj_output.result = read_data[uj_data.num_iterations - 1];
464  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
465  return OK_STATUS();
466 }
467 
468 status_t handle_ibex_sca_tl_read_batch_random(ujson_t *uj) {
469  // Get number of iterations.
470  ibex_sca_batch_t uj_data;
471  TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data));
472  TRY_CHECK(uj_data.num_iterations < 256);
473 
474  // Generate random values.
475  uint32_t values[256];
476  generate_random(uj_data.num_iterations, values);
477 
478  // Get address of buffer located in SRAM.
479  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch;
480  mmio_region_t sram_region_main_addr =
481  mmio_region_from_addr(sram_main_buffer_addr);
482 
483  // Write provided data into SRAM.
484  for (int i = 0; i < uj_data.num_iterations; i++) {
485  mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t),
486  values[i]);
487  }
488 
489  uint32_t read_data[256];
490 
491  // SCA code target.
492 
493  // Fetch data from SRAM.
494  for (int i = 0; i < uj_data.num_iterations; i++) {
495  pentest_set_trigger_high();
496  // Give the trigger time to rise.
497  asm volatile(NOP30);
498  read_data[i] = mmio_region_read32(sram_region_main_addr,
499  i * (ptrdiff_t)sizeof(uint32_t));
500  pentest_set_trigger_low();
501  asm volatile(NOP30);
502  }
503 
504  // Write back last value read from SRAM to validate generated data.
505  ibex_sca_result_t uj_output;
506  uj_output.result = read_data[uj_data.num_iterations - 1];
507  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
508  return OK_STATUS();
509 }
510 
511 status_t handle_ibex_sca_tl_read_batch_random_fix_address(ujson_t *uj) {
512  // Get number of iterations.
513  ibex_sca_batch_t uj_data;
514  TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data));
515  TRY_CHECK(uj_data.num_iterations < 256);
516 
517  // Generate random values.
518  uint32_t values[256];
519  generate_random(uj_data.num_iterations, values);
520 
521  // Get address of buffer located in SRAM.
522  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch;
523  mmio_region_t sram_region_main_addr =
524  mmio_region_from_addr(sram_main_buffer_addr);
525 
526  uint32_t read_data[256];
527  // SCA code target.
528  // Fetch data from SRAM.
529  for (size_t i = 0; i < uj_data.num_iterations; i++) {
530  mmio_region_write32(sram_region_main_addr, 0, values[i]);
531  asm volatile(NOP30);
532  pentest_set_trigger_high();
533  // Give the trigger time to rise.
534  asm volatile(NOP30);
535  read_data[i] = mmio_region_read32(sram_region_main_addr, 0);
536  pentest_set_trigger_low();
537  }
538 
539  // Write back last value read from SRAM to validate generated data.
540  ibex_sca_result_t uj_output;
541  uj_output.result = read_data[uj_data.num_iterations - 1];
542  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
543  return OK_STATUS();
544 }
545 
546 status_t handle_ibex_sca_tl_write(ujson_t *uj) {
547  // Get data to write into SRAM.
548  ibex_sca_test_data_t uj_data;
549  TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data));
550 
551  // Get address of buffer located in SRAM.
552  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer;
553  mmio_region_t sram_region_main_addr =
554  mmio_region_from_addr(sram_main_buffer_addr);
555 
556  // SCA code target.
557  pentest_set_trigger_high();
558  // Give the trigger time to rise.
559  asm volatile(NOP30);
560  // Write provided data into SRAM.
561  for (int i = 0; i < 8; i++) {
562  mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t),
563  uj_data.data[i]);
564  }
565  pentest_set_trigger_low();
566 
567  // Acknowledge test.
568  ibex_sca_result_t uj_output;
569  uj_output.result = 0;
570  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
571  return OK_STATUS();
572 }
573 
574 status_t handle_ibex_sca_tl_write_batch_fvsr(ujson_t *uj) {
575  // Get number of iterations and fixed data.
576  ibex_sca_test_fvsr_t uj_data;
577  TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data));
578  TRY_CHECK(uj_data.num_iterations < 256);
579 
580  // Generate FvsR values.
581  uint32_t values[256];
582  generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values);
583 
584  // Get address of buffer located in SRAM.
585  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch;
586  mmio_region_t sram_region_main_addr =
587  mmio_region_from_addr(sram_main_buffer_addr);
588 
589  // SCA code target.
590  for (int it = 0; it < uj_data.num_iterations; it++) {
591  pentest_set_trigger_high();
592  // Give the trigger time to rise.
593  asm volatile(NOP30);
594  // Write random data into SRAM.
595  mmio_region_write32(sram_region_main_addr, it * (ptrdiff_t)sizeof(uint32_t),
596  values[it]);
597  pentest_set_trigger_low();
598  asm volatile(NOP30);
599  }
600 
601  // Write back last value written into SRAM to validate generated data.
602  ibex_sca_result_t uj_output;
603  uj_output.result = values[uj_data.num_iterations - 1];
604  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
605  return OK_STATUS();
606 }
607 
608 status_t handle_ibex_sca_tl_write_batch_fvsr_fix_address(ujson_t *uj) {
609  // Get number of iterations and fixed data.
610  ibex_sca_test_fvsr_t uj_data;
611  TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data));
612  TRY_CHECK(uj_data.num_iterations < 256);
613 
614  // Generate FvsR values.
615  uint32_t values[256];
616  generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values);
617 
618  // Get address of buffer located in SRAM.
619  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch;
620  mmio_region_t sram_region_main_addr =
621  mmio_region_from_addr(sram_main_buffer_addr);
622 
623  // SCA code target.
624  for (int it = 0; it < uj_data.num_iterations; it++) {
625  pentest_set_trigger_high();
626  // Give the trigger time to rise.
627  asm volatile(NOP30);
628  // Write random data into SRAM at the first address.
629  mmio_region_write32(sram_region_main_addr, 0, values[it]);
630  pentest_set_trigger_low();
631  asm volatile(NOP30);
632  }
633 
634  // Write back last value written into SRAM to validate generated data.
635  ibex_sca_result_t uj_output;
636  uj_output.result = values[uj_data.num_iterations - 1];
637  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
638  return OK_STATUS();
639 }
640 
641 status_t handle_ibex_sca_tl_write_batch_random(ujson_t *uj) {
642  // Get number of iterations.
643  ibex_sca_batch_t uj_data;
644  TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data));
645  TRY_CHECK(uj_data.num_iterations < 256);
646 
647  // Generate random values.
648  uint32_t values[256];
649  generate_random(uj_data.num_iterations, values);
650 
651  // Get address of buffer located in SRAM.
652  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch;
653  mmio_region_t sram_region_main_addr =
654  mmio_region_from_addr(sram_main_buffer_addr);
655 
656  // SCA code target.
657  for (int it = 0; it < uj_data.num_iterations; it++) {
658  pentest_set_trigger_high();
659  // Give the trigger time to rise.
660  asm volatile(NOP30);
661  // Write random data into SRAM.
662  mmio_region_write32(sram_region_main_addr, it * (ptrdiff_t)sizeof(uint32_t),
663  values[it]);
664  pentest_set_trigger_low();
665  asm volatile(NOP30);
666  }
667 
668  // Write back last value written into SRAM to validate generated data.
669  ibex_sca_result_t uj_output;
670  uj_output.result = values[uj_data.num_iterations - 1];
671  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
672  return OK_STATUS();
673 }
674 
675 status_t handle_ibex_sca_tl_write_batch_random_fix_address(ujson_t *uj) {
676  // Get number of iterations.
677  ibex_sca_batch_t uj_data;
678  TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data));
679  TRY_CHECK(uj_data.num_iterations < 256);
680 
681  // Generate random values.
682  uint32_t values[256];
683  generate_random(uj_data.num_iterations, values);
684 
685  // Get address of buffer located in SRAM.
686  uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch;
687  mmio_region_t sram_region_main_addr =
688  mmio_region_from_addr(sram_main_buffer_addr);
689 
690  // SCA code target.
691  for (int it = 0; it < uj_data.num_iterations; it++) {
692  pentest_set_trigger_high();
693  // Give the trigger time to rise.
694  asm volatile(NOP30);
695  // Write random data into SRAM.
696  mmio_region_write32(sram_region_main_addr, 0, values[it]);
697  pentest_set_trigger_low();
698  asm volatile(NOP30);
699  }
700 
701  // Write back last value written into SRAM to validate generated data.
702  ibex_sca_result_t uj_output;
703  uj_output.result = values[uj_data.num_iterations - 1];
704  RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output);
705  return OK_STATUS();
706 }
707 
708 status_t handle_ibex_sca(ujson_t *uj) {
709  ibex_sca_subcommand_t cmd;
710  TRY(ujson_deserialize_ibex_sca_subcommand_t(uj, &cmd));
711  switch (cmd) {
712  case kIbexScaSubcommandInit:
713  return handle_ibex_pentest_init(uj);
714  case kIbexScaSubcommandKeySideloading:
715  return handle_ibex_sca_key_sideloading(uj);
716  case kIbexScaSubcommandRFRead:
717  return handle_ibex_sca_register_file_read(uj);
718  case kIbexScaSubcommandRFReadBatchFvsr:
719  return handle_ibex_sca_register_file_read_batch_fvsr(uj);
720  case kIbexScaSubcommandRFReadBatchRandom:
721  return handle_ibex_sca_register_file_read_batch_random(uj);
722  case kIbexScaSubcommandRFWrite:
723  return handle_ibex_sca_register_file_write(uj);
724  case kIbexScaSubcommandRFWriteBatchFvsr:
725  return handle_ibex_sca_register_file_write_batch_fvsr(uj);
726  case kIbexScaSubcommandRFWriteBatchRandom:
727  return handle_ibex_sca_register_file_write_batch_random(uj);
728  case kIbexScaSubcommandTLRead:
729  return handle_ibex_sca_tl_read(uj);
730  case kIbexScaSubcommandTLReadBatchFvsr:
731  return handle_ibex_sca_tl_read_batch_fvsr(uj);
732  case kIbexScaSubcommandTLReadBatchFvsrFixAddress:
733  return handle_ibex_sca_tl_read_batch_fvsr_fix_address(uj);
734  case kIbexScaSubcommandTLReadBatchRandom:
735  return handle_ibex_sca_tl_read_batch_random(uj);
736  case kIbexScaSubcommandTLReadBatchRandomFixAddress:
737  return handle_ibex_sca_tl_read_batch_random_fix_address(uj);
738  case kIbexScaSubcommandTLWrite:
739  return handle_ibex_sca_tl_write(uj);
740  case kIbexScaSubcommandTLWriteBatchFvsr:
741  return handle_ibex_sca_tl_write_batch_fvsr(uj);
742  case kIbexScaSubcommandTLWriteBatchFvsrFixAddress:
743  return handle_ibex_sca_tl_write_batch_fvsr_fix_address(uj);
744  case kIbexScaSubcommandTLWriteBatchRandom:
745  return handle_ibex_sca_tl_write_batch_random(uj);
746  case kIbexScaSubcommandTLWriteBatchRandomFixAddress:
747  return handle_ibex_sca_tl_write_batch_random_fix_address(uj);
748  default:
749  LOG_ERROR("Unrecognized IBEX SCA subcommand: %d", cmd);
750  return INVALID_ARGUMENT();
751  }
752  return OK_STATUS();
753 }