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