diff --git a/sw/device/sca/lib/prng.c b/sw/device/sca/lib/prng.c index d89ef2600c4dc4..9ad23e3f311066 100644 --- a/sw/device/sca/lib/prng.c +++ b/sw/device/sca/lib/prng.c @@ -158,6 +158,8 @@ __attribute__((noinline)) static uint32_t genrand_int32(void) { void prng_seed(uint32_t seed) { init_by_array(&seed, 1); } +uint32_t prng_rand_uint32(void) { return genrand_int32(); } + uint8_t prng_rand_byte(void) { uint32_t rand = 0; do { diff --git a/sw/device/sca/lib/prng.h b/sw/device/sca/lib/prng.h index 63f20c09df3705..a1380340f4cc02 100644 --- a/sw/device/sca/lib/prng.h +++ b/sw/device/sca/lib/prng.h @@ -33,6 +33,16 @@ extern "C" { */ void prng_seed(uint32_t seed); +/** + * Generates a random uint32_t. + * + * The behavior of this function matches the behavior of `random.randint(0, + * 0xFFFFFFFF)` in python. + * + * @return A random uint32_t. + */ +uint32_t prng_rand_uint32(void); + /** * Generates a random byte. * diff --git a/sw/device/tests/crypto/cryptotest/firmware/BUILD b/sw/device/tests/crypto/cryptotest/firmware/BUILD index b6e126dc6d04bb..ad13c57eebb335 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/BUILD +++ b/sw/device/tests/crypto/cryptotest/firmware/BUILD @@ -169,10 +169,7 @@ cc_library( cc_library( name = "ibex_fi", srcs = ["ibex_fi.c"], - hdrs = [ - "ibex_fi.h", - "status.h", - ], + hdrs = ["ibex_fi.h"], deps = [ "//sw/device/lib/base:memory", "//sw/device/lib/base:status", @@ -191,16 +188,15 @@ cc_library( cc_library( name = "ibex_sca", srcs = ["ibex_sca.c"], - hdrs = [ - "ibex_sca.h", - "status.h", - ], + hdrs = ["ibex_sca.h"], deps = [ "//sw/device/lib/base:memory", "//sw/device/lib/base:status", "//sw/device/lib/runtime:log", + "//sw/device/lib/testing/test_framework:check", "//sw/device/lib/testing/test_framework:ujson_ottf", "//sw/device/lib/ujson", + "//sw/device/sca/lib:prng", "//sw/device/sca/lib:sca", "//sw/device/tests/crypto/cryptotest/firmware:sca_lib", "//sw/device/tests/crypto/cryptotest/json:ibex_sca_commands", diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c index ae60d3aedd7071..2bdfedb6ae7197 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c @@ -15,7 +15,6 @@ #include "sw/device/lib/ujson/ujson.h" #include "sw/device/sca/lib/sca.h" #include "sw/device/tests/crypto/cryptotest/firmware/sca_lib.h" -#include "sw/device/tests/crypto/cryptotest/firmware/status.h" #include "sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h" #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" @@ -89,28 +88,12 @@ static dif_flash_ctrl_device_info_t flash_info; // used by the program. OT_SECTION(".data") static volatile uint32_t sram_main_buffer[32]; +static volatile uint32_t sram_main_buffer_large[4000]; -/** - * ibex.char.flash_read command handler. - * - * This FI penetration tests executes the following instructions: - * - Write reference values into flash. - * - Set the trigger. - * - Add 10 NOPs to delay the trigger - * - Read values from flash. - * - Unset the trigger. - * - Compare the values. - * - Return the values over UART. - * - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_flash_read(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -129,10 +112,8 @@ status_t handle_ibex_fi_char_flash_read(ujson_t *uj) { .size = 0x1, .properties = region_properties}; - UJSON_CHECK_DIF_OK( - dif_flash_ctrl_set_data_region_properties(&flash, 0, data_region)); - UJSON_CHECK_DIF_OK( - dif_flash_ctrl_set_data_region_enablement(&flash, 0, kDifToggleEnabled)); + TRY(dif_flash_ctrl_set_data_region_properties(&flash, 0, data_region)); + TRY(dif_flash_ctrl_set_data_region_enablement(&flash, 0, kDifToggleEnabled)); ptrdiff_t flash_bank_1_addr = (ptrdiff_t)flash_info.data_pages * (ptrdiff_t)flash_info.bytes_per_page; @@ -147,7 +128,7 @@ status_t handle_ibex_fi_char_flash_read(ujson_t *uj) { } // Erase flash and write page with reference values. - UJSON_CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page( + TRY(flash_ctrl_testutils_erase_and_write_page( &flash, (uint32_t)flash_bank_1_addr, /*partition_id=*/0, input_page, kDifFlashCtrlPartitionTypeData, FLASH_UINT32_WORDS_PER_PAGE)); @@ -170,7 +151,7 @@ status_t handle_ibex_fi_char_flash_read(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send res & ERR_STATUS to host. ibex_fi_test_result_t uj_output; @@ -180,26 +161,10 @@ status_t handle_ibex_fi_char_flash_read(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.flash_write command handler. - * - * This FI penetration tests executes the following instructions: - * - Set the trigger. - * - Add 10 NOPs to delay the trigger - * - Write 32 values into flash. - * - Unset the trigger. - * - Read back values and compare. - * - Return the values over UART. - * - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_flash_write(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); // Configure the data flash. @@ -215,10 +180,8 @@ status_t handle_ibex_fi_char_flash_write(ujson_t *uj) { .base = FLASH_PAGES_PER_BANK, .size = 0x1, .properties = region_properties}; - UJSON_CHECK_DIF_OK( - dif_flash_ctrl_set_data_region_properties(&flash, 0, data_region)); - UJSON_CHECK_DIF_OK( - dif_flash_ctrl_set_data_region_enablement(&flash, 0, kDifToggleEnabled)); + TRY(dif_flash_ctrl_set_data_region_properties(&flash, 0, data_region)); + TRY(dif_flash_ctrl_set_data_region_enablement(&flash, 0, kDifToggleEnabled)); ptrdiff_t flash_bank_1_addr = (ptrdiff_t)flash_info.data_pages * (ptrdiff_t)flash_info.bytes_per_page; @@ -235,7 +198,7 @@ status_t handle_ibex_fi_char_flash_write(ujson_t *uj) { // FI code target. sca_set_trigger_high(); // Erase flash and write page with reference values. - UJSON_CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page( + TRY(flash_ctrl_testutils_erase_and_write_page( &flash, (uint32_t)flash_bank_1_addr, /*partition_id=*/0, input_page, kDifFlashCtrlPartitionTypeData, FLASH_UINT32_WORDS_PER_PAGE)); sca_set_trigger_low(); @@ -253,7 +216,7 @@ status_t handle_ibex_fi_char_flash_write(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send res & ERR_STATUS to host. ibex_fi_test_result_t uj_output; @@ -263,27 +226,61 @@ status_t handle_ibex_fi_char_flash_write(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.sram_read command handler. - * - * This FI penetration tests executes the following instructions: - * - Write reference values into SRAM. - * - Set the trigger. - * - Add 10 NOPs to delay the trigger - * - Read values from SRAM. - * - Unset the trigger. - * - Compare the values. - * - Return the values over UART. - * - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ +status_t handle_ibex_fi_char_sram_static(ujson_t *uj) { + // Configure Ibex to allow reading ERR_STATUS register. + dif_rv_core_ibex_t rv_core_ibex; + TRY(dif_rv_core_ibex_init( + mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), + &rv_core_ibex)); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_large; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // Write reference value into SRAM. + for (int i = 0; i < 4000; i++) { + mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t), + ref_values[0]); + } + + // FI code target. + sca_set_trigger_high(); + asm volatile(NOP1000); + sca_set_trigger_low(); + + // Compare against reference values. + ibex_fi_faulty_addresses_t uj_output; + memset(uj_output.addresses, 0, sizeof(uj_output.addresses)); + int faulty_address_pos = 0; + for (int sram_pos = 0; sram_pos < 4000; sram_pos++) { + uint32_t res_value = mmio_region_read32( + sram_region_main_addr, sram_pos * (ptrdiff_t)sizeof(uint32_t)); + if (res_value != ref_values[0]) { + uj_output.addresses[faulty_address_pos] = (uint32_t)sram_pos; + faulty_address_pos++; + // Currently, we register only up to 8 faulty SRAM positions. If there + // are more, we overwrite the addresses array. + if (faulty_address_pos > 7) { + faulty_address_pos = 0; + } + } + } + + // Read ERR_STATUS register. + dif_rv_core_ibex_error_status_t codes; + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + + // Send res & ERR_STATUS to host. + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_faulty_addresses_t, uj, &uj_output); + return OK_STATUS(0); +} + status_t handle_ibex_fi_char_sram_read(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -317,7 +314,7 @@ status_t handle_ibex_fi_char_sram_read(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send res & ERR_STATUS to host. ibex_fi_test_result_t uj_output; @@ -327,26 +324,10 @@ status_t handle_ibex_fi_char_sram_read(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.sram_write command handler. - * - * This FI penetration tests executes the following instructions: - * - Set the trigger. - * - Add 10 NOPs to delay the trigger - * - Write 32 values into SRAM. - * - Unset the trigger. - * - Read back values and compare. - * - Return the values over UART. - * - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_sram_write(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -376,7 +357,7 @@ status_t handle_ibex_fi_char_sram_write(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send res & ERR_STATUS to host. ibex_fi_test_result_t uj_output; @@ -386,24 +367,10 @@ status_t handle_ibex_fi_char_sram_write(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.unconditional_branch command handler. - * - * This FI penetration tests executes the following instructions: - * - Add 10 NOPs to delay the trigger - * - 10000 iterations with a for loop: - * - Execute an unconditional branch instruction - * - Increment variable - * - Return the values over UART. - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_unconditional_branch(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -515,7 +482,7 @@ status_t handle_ibex_fi_char_unconditional_branch(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send loop counters & ERR_STATUS to host. ibex_fi_test_result_t uj_output; @@ -525,24 +492,10 @@ status_t handle_ibex_fi_char_unconditional_branch(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.conditional_branch command handler. - * - * This FI penetration tests executes the following instructions: - * - Add 10 NOPs to delay the trigger - * - 10000 iterations with a for loop: - * - Execute a branch instruction - * - Increment variable if branch is taken or not - * - Return the values over UART. - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_conditional_branch(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -562,7 +515,7 @@ status_t handle_ibex_fi_char_conditional_branch(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send loop counters & ERR_STATUS to host. ibex_fi_test_result_mult_t uj_output; @@ -573,28 +526,10 @@ status_t handle_ibex_fi_char_conditional_branch(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.mem_op_loop command handler. - * - * This FI penetration tests executes the following instructions: - * - Add 100 NOPs to delay the trigger - * - 10000 iterations with a for loop: - * - Load loop_counter1 value into x5: lw x5, (&loop_counter1) - * - Increment loop counter1: addi x5, x5, 1 - * - Store loop counter1 back to loop_counter1: sw x5, (&loop_counter1) - * - Load loop_counter2 value into x6: lw x6, (&loop_counter2) - * - Decrement loop counter2: addi x6, x6, -1 - * - Store loop counter2 back to loop_counter2: sw x6, (&loop_counter2) - * - Return the values over UART. - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_mem_op_loop(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -611,7 +546,7 @@ status_t handle_ibex_fi_char_mem_op_loop(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send loop counters & ERR_STATUS to host. ibex_fi_loop_counter_mirrored_t uj_output; @@ -622,25 +557,10 @@ status_t handle_ibex_fi_char_mem_op_loop(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.unrolled_mem_op_loop command handler. - * - * This FI penetration tests executes the following instructions: - * - Add 100 NOPs to delay the trigger - * - 10000 iterations: - * - Load loop_counter value into x5: lw x5, (&loop_counter) - * - Increment loop counter: addi x5, x5, 1 - * - Store loop counter back to loop_counter: sw x5, (&loop_counter) - * - Return the value over UART. - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_unrolled_mem_op_loop(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -662,7 +582,7 @@ status_t handle_ibex_fi_char_unrolled_mem_op_loop(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send loop counter & ERR_STATUS to host. ibex_fi_loop_counter_t uj_output; @@ -672,24 +592,10 @@ status_t handle_ibex_fi_char_unrolled_mem_op_loop(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.reg_op_loop command handler. - * - * This FI penetration tests executes the following instructions: - * - Initialize register x5=0 & x6=10000 - * - Add 100 NOPs to delay the trigger - * - Perform 10000 x5 = x5 + 1 additions and x6 = x6 - 1 subtractions - * - Return the values over UART. - * - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_reg_op_loop(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -710,7 +616,7 @@ status_t handle_ibex_fi_char_reg_op_loop(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send loop counters & ERR_STATUS to host. ibex_fi_loop_counter_mirrored_t uj_output; @@ -721,24 +627,10 @@ status_t handle_ibex_fi_char_reg_op_loop(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.unrolled_reg_op_loop command handler. - * - * This FI penetration tests executes the following instructions: - * - Initialize register x5=0 - * - Add 100 NOPs to delay the trigger - * - Perform 10000 x5 = x5 + 1 additions - * - Return the value over UART. - * - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_unrolled_reg_op_loop(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -762,7 +654,7 @@ status_t handle_ibex_fi_char_unrolled_reg_op_loop(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send loop counter & ERR_STATUS to host. ibex_fi_loop_counter_t uj_output; @@ -772,23 +664,10 @@ status_t handle_ibex_fi_char_unrolled_reg_op_loop(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.register_file command handler. - * - * This FI penetration test executes the following instructions: - * - Initialize temp. registers with reference values - * - Execute 1000 NOPs - * - Read back temp. register values and compare against reference values - * - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_register_file(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -828,7 +707,7 @@ status_t handle_ibex_fi_char_register_file(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send result & ERR_STATUS to host. ibex_fi_test_result_t uj_output; @@ -838,23 +717,10 @@ status_t handle_ibex_fi_char_register_file(ujson_t *uj) { return OK_STATUS(0); } -/** - * ibex.char.register_file_read command handler. - * - * This FI penetration test executes the following instructions: - * - Initialize temp. registers with reference values - * - Read these registers. - * - Compare against reference values - * - * Faults are injected during the trigger_high & trigger_low. - * It needs to be ensured that the compiler does not optimize this code. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_char_register_file_read(ujson_t *uj) { // Configure Ibex to allow reading ERR_STATUS register. dif_rv_core_ibex_t rv_core_ibex; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + TRY(dif_rv_core_ibex_init( mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); @@ -891,7 +757,7 @@ status_t handle_ibex_fi_char_register_file_read(ujson_t *uj) { // Read ERR_STATUS register. dif_rv_core_ibex_error_status_t codes; - UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); // Send result & ERR_STATUS to host. ibex_fi_test_result_t uj_output; @@ -901,12 +767,6 @@ status_t handle_ibex_fi_char_register_file_read(ujson_t *uj) { return OK_STATUS(0); } -/** - * Initializes the trigger. - * - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi_init_trigger(ujson_t *uj) { sca_select_trigger_type(kScaTriggerTypeSw); // As we are using the software defined trigger, the first argument of @@ -918,20 +778,13 @@ status_t handle_ibex_fi_init_trigger(ujson_t *uj) { // Enable the flash. flash_info = dif_flash_ctrl_get_device_info(); - UJSON_CHECK_DIF_OK(dif_flash_ctrl_init_state( + TRY(dif_flash_ctrl_init_state( &flash, mmio_region_from_addr(TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR))); - UJSON_CHECK_STATUS_OK(flash_ctrl_testutils_wait_for_init(&flash)); + TRY(flash_ctrl_testutils_wait_for_init(&flash)); return OK_STATUS(0); } -/** - * Ibex FI command handler. - * - * Command handler for the Ibex FI command. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_fi(ujson_t *uj) { ibex_fi_subcommand_t cmd; TRY(ujson_deserialize_ibex_fi_subcommand_t(uj, &cmd)); @@ -958,6 +811,8 @@ status_t handle_ibex_fi(ujson_t *uj) { return handle_ibex_fi_char_sram_write(uj); case kIbexFiSubcommandCharSramRead: return handle_ibex_fi_char_sram_read(uj); + case kIbexFiSubcommandCharSramStatic: + return handle_ibex_fi_char_sram_static(uj); case kIbexFiSubcommandCharFlashWrite: return handle_ibex_fi_char_flash_write(uj); case kIbexFiSubcommandCharFlashRead: diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h index 2e9f8d795b671c..51d93ae2d6ef64 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h @@ -8,19 +8,258 @@ #include "sw/device/lib/base/status.h" #include "sw/device/lib/ujson/ujson.h" +/** + * ibex.fi.char.flash_read command handler. + * + * This FI penetration tests executes the following instructions: + * - Write reference values into flash. + * - Set the trigger. + * - Add 10 NOPs to delay the trigger + * - Read values from flash. + * - Unset the trigger. + * - Compare the values. + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_flash_read(ujson_t *uj); + +/** + * ibex.fi.char.flash_write command handler. + * + * This FI penetration tests executes the following instructions: + * - Set the trigger. + * - Add 10 NOPs to delay the trigger + * - Write 32 values into flash. + * - Unset the trigger. + * - Read back values and compare. + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_flash_write(ujson_t *uj); + +/** + * ibex.fi.char.sram_static command handler. + * + * This FI penetration tests executes the following instructions: + * - Write ref_values[0] to 16kb of SRAM. + * - Set the trigger. + * - Add 1000 NOPs to give the setup the chance to inject faults. + * - Unset the trigger. + * - Read back content of 16kb of SRAM and compare against reference value. + * - If faulty words are detected, transmit addresses back to host. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_fi_char_sram_static(ujson_t *uj); + +/** + * ibex.fi.char.sram_read command handler. + * + * This FI penetration tests executes the following instructions: + * - Write reference values into SRAM. + * - Set the trigger. + * - Add 10 NOPs to delay the trigger + * - Read values from SRAM. + * - Unset the trigger. + * - Compare the values. + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_sram_read(ujson_t *uj); + +/** + * ibex.fi.char.sram_write command handler. + * + * This FI penetration tests executes the following instructions: + * - Set the trigger. + * - Add 10 NOPs to delay the trigger + * - Write 32 values into SRAM. + * - Unset the trigger. + * - Read back values and compare. + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_sram_write(ujson_t *uj); + +/** + * ibex.fi.char.unconditional_branch command handler. + * + * This FI penetration tests executes the following instructions: + * - Add 10 NOPs to delay the trigger + * - 10000 iterations with a for loop: + * - Execute an unconditional branch instruction + * - Increment variable + * - Return the values over UART. + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_unconditional_branch(ujson_t *uj); + +/** + * ibex.fi.char.conditional_branch command handler. + * + * This FI penetration tests executes the following instructions: + * - Add 10 NOPs to delay the trigger + * - 10000 iterations with a for loop: + * - Execute a branch instruction + * - Increment variable if branch is taken or not + * - Return the values over UART. + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_conditional_branch(ujson_t *uj); + +/** + * ibex.fi.char.mem_op_loop command handler. + * + * This FI penetration tests executes the following instructions: + * - Add 100 NOPs to delay the trigger + * - 10000 iterations with a for loop: + * - Load loop_counter1 value into x5: lw x5, (&loop_counter1) + * - Increment loop counter1: addi x5, x5, 1 + * - Store loop counter1 back to loop_counter1: sw x5, (&loop_counter1) + * - Load loop_counter2 value into x6: lw x6, (&loop_counter2) + * - Decrement loop counter2: addi x6, x6, -1 + * - Store loop counter2 back to loop_counter2: sw x6, (&loop_counter2) + * - Return the values over UART. + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_mem_op_loop(ujson_t *uj); + +/** + * ibex.fi.char.reg_op_loop command handler. + * + * This FI penetration tests executes the following instructions: + * - Initialize register x5=0 & x6=10000 + * - Add 100 NOPs to delay the trigger + * - Perform 10000 x5 = x5 + 1 additions and x6 = x6 - 1 subtractions + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_reg_op_loop(ujson_t *uj); + +/** + * ibex.fi.char.unrolled_mem_op_loop command handler. + * + * This FI penetration tests executes the following instructions: + * - Add 100 NOPs to delay the trigger + * - 10000 iterations: + * - Load loop_counter value into x5: lw x5, (&loop_counter) + * - Increment loop counter: addi x5, x5, 1 + * - Store loop counter back to loop_counter: sw x5, (&loop_counter) + * - Return the value over UART. + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_unrolled_mem_op_loop(ujson_t *uj); + +/** + * ibex.fi.char.unrolled_reg_op_loop command handler. + * + * This FI penetration tests executes the following instructions: + * - Initialize register x5=0 + * - Add 100 NOPs to delay the trigger + * - Perform 10000 x5 = x5 + 1 additions + * - Return the value over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_unrolled_reg_op_loop(ujson_t *uj); + +/** + * Initializes the trigger and configures the device for the Ibex FI test. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_init_trigger(ujson_t *uj); + +/** + * ibex.fi.char.register_file command handler. + * + * This FI penetration test executes the following instructions: + * - Initialize temp. registers with reference values + * - Execute 1000 NOPs + * - Read back temp. register values and compare against reference values + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_register_file(ujson_t *uj); + +/** + * ibex.fi.char.register_file_read command handler. + * + * This FI penetration test executes the following instructions: + * - Initialize temp. registers with reference values + * - Read these registers. + * - Compare against reference values + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_register_file_read(ujson_t *uj); + +/** + * Ibex FI command handler. + * + * Command handler for the Ibex FI command. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi(ujson_t *uj); #endif // OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_IBEX_FI_H_ diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c index fbaec64bcee857..6b1d466c7bf0b6 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c @@ -7,35 +7,186 @@ #include "sw/device/lib/base/memory.h" #include "sw/device/lib/base/status.h" #include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/test_framework/check.h" #include "sw/device/lib/testing/test_framework/ottf_test_config.h" #include "sw/device/lib/testing/test_framework/ujson_ottf.h" #include "sw/device/lib/ujson/ujson.h" +#include "sw/device/sca/lib/prng.h" #include "sw/device/sca/lib/sca.h" #include "sw/device/tests/crypto/cryptotest/firmware/sca_lib.h" -#include "sw/device/tests/crypto/cryptotest/firmware/status.h" #include "sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h" #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" +// NOP macros. +#define NOP1 "addi x0, x0, 0\n" +#define NOP10 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 NOP1 +#define NOP100 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 + // Buffer to allow the compiler to allocate a safe area in Main SRAM where // we can do the write/read test without the risk of clobbering data // used by the program. OT_SECTION(".data") static volatile uint32_t sram_main_buffer[8]; +static volatile uint32_t sram_main_buffer_batch[256]; + +// Generate Fixed vs Random (FvsR) array of values. The fixed value is provided +// by the user and the random values are generated by the PRNG provided in the +// SCA library. +static void generate_fvsr(size_t num_iterations, uint32_t fixed_data, + uint32_t values[]) { + bool sample_fixed = true; + for (size_t i = 0; i < num_iterations; i++) { + if (sample_fixed) { + values[i] = fixed_data; + } else { + values[i] = prng_rand_uint32(); + } + sample_fixed = prng_rand_uint32() & 0x1; + } +} + +// Generate random values used by the test by calling the SCA PRNG. +static void generate_random(size_t num_iterations, uint32_t values[]) { + for (size_t i = 0; i < num_iterations; i++) { + values[i] = prng_rand_uint32(); + } +} + +status_t handle_ibex_sca_tl_write_batch_fvsr_fix_address(ujson_t *uj) { + // Get number of iterations and fixed data. + ibex_sca_test_fvsr_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate FvsR values. + uint32_t values[256]; + generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // SCA code target. + for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Write random data into SRAM at the first address. + mmio_region_write32(sram_region_main_addr, 0, values[it]); + sca_set_trigger_low(); + asm volatile(NOP100); + } + + // Write back last value written into SRAM to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = values[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_tl_write_batch_fvsr(ujson_t *uj) { + // Get number of iterations and fixed data. + ibex_sca_test_fvsr_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate FvsR values. + uint32_t values[256]; + generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // SCA code target. + for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Write random data into SRAM. + mmio_region_write32(sram_region_main_addr, it * (ptrdiff_t)sizeof(uint32_t), + values[it]); + sca_set_trigger_low(); + asm volatile(NOP100); + } + + // Write back last value written into SRAM to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = values[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_tl_write_batch_random_fix_address(ujson_t *uj) { + // Get number of iterations. + ibex_sca_batch_t uj_data; + TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate random values. + uint32_t values[256]; + generate_random(uj_data.num_iterations, values); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // SCA code target. + for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Write random data into SRAM. + mmio_region_write32(sram_region_main_addr, 0, values[it]); + sca_set_trigger_low(); + asm volatile(NOP100); + } + + // Write back last value written into SRAM to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = values[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_tl_write_batch_random(ujson_t *uj) { + // Get number of iterations. + ibex_sca_batch_t uj_data; + TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate random values. + uint32_t values[256]; + generate_random(uj_data.num_iterations, values); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // SCA code target. + for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Write random data into SRAM. + mmio_region_write32(sram_region_main_addr, it * (ptrdiff_t)sizeof(uint32_t), + values[it]); + sca_set_trigger_low(); + asm volatile(NOP100); + } + + // Write back last value written into SRAM to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = values[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} -/** - * ibex.sca.tl_write - * - * This SCA penetration test executes the following instructions: - * - Loop num_iterations: - * - Set trigger - * - Write data over TL-UL into SRAM. - * - Unset trigger - * - * SCA traces are captured during trigger_high & trigger_low. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_sca_tl_write(ujson_t *uj) { // Get data to write into SRAM. ibex_sca_test_data_t uj_data; @@ -47,36 +198,179 @@ status_t handle_ibex_sca_tl_write(ujson_t *uj) { mmio_region_from_addr(sram_main_buffer_addr); // SCA code target. - for (int it = 0; it < uj_data.num_iterations; it++) { - sca_set_trigger_high(); - // Write provided data into SRAM. - for (int i = 0; i < 8; i++) { - mmio_region_write32(sram_region_main_addr, - i * (ptrdiff_t)sizeof(uint32_t), uj_data.data[i]); - } - sca_set_trigger_low(); + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Write provided data into SRAM. + for (int i = 0; i < 8; i++) { + mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t), + uj_data.data[i]); } + sca_set_trigger_low(); // Acknowledge test. ibex_sca_result_t uj_output; uj_output.result = 0; RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); - return OK_STATUS(0); -} - -/** - * ibex.sca.tl_read - * - * This SCA penetration test executes the following instructions: - * - Loop num_iterations: - * - Set trigger - * - Read data from SRAM over TL-UL. - * - Unset trigger - * - * SCA traces are captured during trigger_high & trigger_low. - * - * @param uj The received uJSON data. - */ + return OK_STATUS(); +} + +status_t handle_ibex_sca_tl_read_batch_fvsr_fix_address(ujson_t *uj) { + // Get number of iterations and fixed data. + ibex_sca_test_fvsr_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate FvsR values. + uint32_t values[256]; + generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + uint32_t read_data[256]; + + // SCA code target. + // Fetch data from SRAM. + for (size_t i = 0; i < uj_data.num_iterations; i++) { + mmio_region_write32(sram_region_main_addr, 0, values[i]); + asm volatile(NOP100); + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + read_data[i] = mmio_region_read32(sram_region_main_addr, 0); + sca_set_trigger_low(); + } + + // Write back last value read from SRAM to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = read_data[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_tl_read_batch_fvsr(ujson_t *uj) { + // Get number of iterations and fixed data. + ibex_sca_test_fvsr_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate FvsR values. + uint32_t values[256]; + generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // Write provided data into SRAM. + for (size_t i = 0; i < uj_data.num_iterations; i++) { + mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t), + values[i]); + } + + uint32_t read_data[256]; + + // SCA code target. + // Fetch data from SRAM. + for (size_t i = 0; i < uj_data.num_iterations; i++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + read_data[i] = mmio_region_read32(sram_region_main_addr, + i * (ptrdiff_t)sizeof(uint32_t)); + sca_set_trigger_low(); + asm volatile(NOP100); + } + + // Write back last value read from SRAM to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = read_data[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_tl_read_batch_random_fix_address(ujson_t *uj) { + // Get number of iterations. + ibex_sca_batch_t uj_data; + TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate random values. + uint32_t values[256]; + generate_random(uj_data.num_iterations, values); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + uint32_t read_data[256]; + // SCA code target. + // Fetch data from SRAM. + for (size_t i = 0; i < uj_data.num_iterations; i++) { + mmio_region_write32(sram_region_main_addr, 0, values[i]); + asm volatile(NOP100); + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + read_data[i] = mmio_region_read32(sram_region_main_addr, 0); + sca_set_trigger_low(); + } + + // Write back last value read from SRAM to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = read_data[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_tl_read_batch_random(ujson_t *uj) { + // Get number of iterations. + ibex_sca_batch_t uj_data; + TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate random values. + uint32_t values[256]; + generate_random(uj_data.num_iterations, values); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer_batch; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // Write provided data into SRAM. + for (size_t i = 0; i < uj_data.num_iterations; i++) { + mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t), + values[i]); + } + + uint32_t read_data[256]; + + // SCA code target. + + // Fetch data from SRAM. + for (size_t i = 0; i < uj_data.num_iterations; i++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + read_data[i] = mmio_region_read32(sram_region_main_addr, + i * (ptrdiff_t)sizeof(uint32_t)); + sca_set_trigger_low(); + asm volatile(NOP100); + } + + // Write back last value read from SRAM to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = read_data[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + status_t handle_ibex_sca_tl_read(ujson_t *uj) { // Get data to write into SRAM. ibex_sca_test_data_t uj_data; @@ -96,72 +390,190 @@ status_t handle_ibex_sca_tl_read(ujson_t *uj) { uint32_t read_data[8]; // SCA code target. - for (int it = 0; it < uj_data.num_iterations; it++) { - sca_set_trigger_high(); - // Fetch data from SRAM. - for (int i = 0; i < 8; i++) { - read_data[i] = mmio_region_read32(sram_region_main_addr, - i * (ptrdiff_t)sizeof(uint32_t)); - } - sca_set_trigger_low(); + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Fetch data from SRAM. + for (int i = 0; i < 8; i++) { + read_data[i] = mmio_region_read32(sram_region_main_addr, + i * (ptrdiff_t)sizeof(uint32_t)); } + sca_set_trigger_low(); // Acknowledge test. ibex_sca_result_t uj_output; uj_output.result = 0; RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); - return OK_STATUS(0); -} - -/** - * ibex.sca.register_file_write - * - * This SCA penetration test executes the following instructions: - * - Loop num_iterations: - * - Set trigger - * - Write provided data to registers in RF - * - Unset trigger - * - * SCA traces are captured during trigger_high & trigger_low. - * - * @param uj The received uJSON data. - */ + return OK_STATUS(); +} + +status_t handle_ibex_sca_register_file_write_batch_fvsr(ujson_t *uj) { + // Get number of iterations and fixed data. + ibex_sca_test_fvsr_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate FvsR values. + uint32_t values[256]; + generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values); + + // SCA code target. + for (size_t i = 0; i < uj_data.num_iterations; i++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Write provided data into register file. + asm volatile("mv x5, %0" : : "r"(values[i])); + asm volatile("mv x6, %0" : : "r"(values[i])); + asm volatile("mv x7, %0" : : "r"(values[i])); + asm volatile("mv x28, %0" : : "r"(values[i])); + asm volatile("mv x29, %0" : : "r"(values[i])); + asm volatile("mv x30, %0" : : "r"(values[i])); + asm volatile("mv x31, %0" : : "r"(values[i])); + sca_set_trigger_low(); + asm volatile(NOP100); + } + + // Write back last value written into the RF to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = values[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_register_file_write_batch_random(ujson_t *uj) { + // Get number of iterations. + ibex_sca_batch_t uj_data; + TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate random values. + uint32_t values[256]; + generate_random(uj_data.num_iterations, values); + + // SCA code target. + for (size_t i = 0; i < uj_data.num_iterations; i++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Write provided data into register file. + asm volatile("mv x5, %0" : : "r"(values[i])); + asm volatile("mv x6, %0" : : "r"(values[i])); + asm volatile("mv x7, %0" : : "r"(values[i])); + asm volatile("mv x28, %0" : : "r"(values[i])); + asm volatile("mv x29, %0" : : "r"(values[i])); + asm volatile("mv x30, %0" : : "r"(values[i])); + asm volatile("mv x31, %0" : : "r"(values[i])); + sca_set_trigger_low(); + asm volatile(NOP100); + } + + // Write back last value written into the RF to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = values[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + status_t handle_ibex_sca_register_file_write(ujson_t *uj) { // Get data to write into RF. ibex_sca_test_data_t uj_data; TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data)); + // SCA code target. - for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Write provided data into register file. + asm volatile("mv x5, %0" : : "r"(uj_data.data[0])); + asm volatile("mv x6, %0" : : "r"(uj_data.data[1])); + asm volatile("mv x7, %0" : : "r"(uj_data.data[2])); + asm volatile("mv x28, %0" : : "r"(uj_data.data[3])); + asm volatile("mv x29, %0" : : "r"(uj_data.data[4])); + asm volatile("mv x30, %0" : : "r"(uj_data.data[5])); + asm volatile("mv x31, %0" : : "r"(uj_data.data[6])); + sca_set_trigger_low(); + + // Acknowledge test. + ibex_sca_result_t uj_output; + uj_output.result = 0; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_register_file_read_batch_fvsr(ujson_t *uj) { + // Get number of iterations and fixed data. + ibex_sca_test_fvsr_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_fvsr_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate FvsR values. + uint32_t values[256]; + generate_fvsr(uj_data.num_iterations, uj_data.fixed_data, values); + + for (size_t i = 0; i < uj_data.num_iterations; i++) { + // Initialize temporary registers with reference values. + asm volatile("mv x5, %0" : : "r"(0)); + asm volatile("mv x6, %0" : : "r"(0)); + asm volatile("mv x7, %0" : : "r"(0)); + asm volatile("mv x28, %0" : : "r"(values[i])); + asm volatile("mv x29, %0" : : "r"(values[i])); + asm volatile("mv x30, %0" : : "r"(values[i])); + asm volatile(NOP100); + // SCA code target. sca_set_trigger_high(); - // Write provided data into register file. - asm volatile("mv x5, %0" : : "r"(uj_data.data[0])); - asm volatile("mv x6, %0" : : "r"(uj_data.data[1])); - asm volatile("mv x7, %0" : : "r"(uj_data.data[2])); - asm volatile("mv x28, %0" : : "r"(uj_data.data[3])); - asm volatile("mv x29, %0" : : "r"(uj_data.data[4])); - asm volatile("mv x30, %0" : : "r"(uj_data.data[5])); - asm volatile("mv x31, %0" : : "r"(uj_data.data[6])); + // Give the trigger time to rise. + asm volatile(NOP100); + // Copy registers. + asm volatile("mv x5, x28"); + asm volatile("mv x6, x29"); + asm volatile("mv x7, x30"); sca_set_trigger_low(); } - // Acknowledge test. + + // Write back last value written into the RF to validate generated data. ibex_sca_result_t uj_output; - uj_output.result = 0; + uj_output.result = values[uj_data.num_iterations - 1]; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_sca_register_file_read_batch_random(ujson_t *uj) { + // Get number of iterations. + ibex_sca_batch_t uj_data; + TRY(ujson_deserialize_ibex_sca_batch_t(uj, &uj_data)); + TRY_CHECK(uj_data.num_iterations < 256); + + // Generate random values. + uint32_t values[256]; + generate_random(uj_data.num_iterations, values); + + for (size_t i = 0; i < uj_data.num_iterations; i++) { + // Initialize temporary registers with reference values. + asm volatile("mv x5, %0" : : "r"(0)); + asm volatile("mv x6, %0" : : "r"(0)); + asm volatile("mv x7, %0" : : "r"(0)); + asm volatile("mv x28, %0" : : "r"(values[i])); + asm volatile("mv x29, %0" : : "r"(values[i])); + asm volatile("mv x30, %0" : : "r"(values[i])); + asm volatile(NOP100); + // SCA code target. + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Copy registers. + asm volatile("mv x5, x28"); + asm volatile("mv x6, x29"); + asm volatile("mv x7, x30"); + sca_set_trigger_low(); + } + + // Write back last value written into the RF to validate generated data. + ibex_sca_result_t uj_output; + uj_output.result = values[uj_data.num_iterations - 1]; RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); - return OK_STATUS(0); -} - -/** - * ibex.sca.register_file_read - * - * This SCA penetration test executes the following instructions: - * - Loop num_iterations: - * - Set trigger - * - Read data from RF - * - Unset trigger - * - * SCA traces are captured during trigger_high & trigger_low. - * - * @param uj The received uJSON data. - */ + return OK_STATUS(); +} + status_t handle_ibex_sca_register_file_read(ujson_t *uj) { // Get data to write into RF. ibex_sca_test_data_t uj_data; @@ -175,27 +587,22 @@ status_t handle_ibex_sca_register_file_read(ujson_t *uj) { asm volatile("mv x30, %0" : : "r"(uj_data.data[5])); // SCA code target. - for (int it = 0; it < uj_data.num_iterations; it++) { - sca_set_trigger_high(); - // Copy registers. - asm volatile("mv x28, x5"); - asm volatile("mv x29, x6"); - asm volatile("mv x30, x7"); - sca_set_trigger_low(); - } + sca_set_trigger_high(); + // Give the trigger time to rise. + asm volatile(NOP100); + // Copy registers. + asm volatile("mv x28, x5"); + asm volatile("mv x29, x6"); + asm volatile("mv x30, x7"); + sca_set_trigger_low(); + // Acknowledge test. ibex_sca_result_t uj_output; uj_output.result = 0; RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * Initializes the Ibex SCA test. - * - * - * @param uj The received uJSON data. - */ status_t handle_ibex_sca_init(ujson_t *uj) { // Setup trigger and enable peripherals needed for the test. sca_select_trigger_type(kScaTriggerTypeSw); @@ -206,16 +613,9 @@ status_t handle_ibex_sca_init(ujson_t *uj) { // Disable the instruction cache and dummy instructions for SCA. sca_configure_cpu(); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * Ibex SCA command handler. - * - * Command handler for the Ibex SCA command. - * - * @param uj The received uJSON data. - */ status_t handle_ibex_sca(ujson_t *uj) { ibex_sca_subcommand_t cmd; TRY(ujson_deserialize_ibex_sca_subcommand_t(uj, &cmd)); @@ -224,15 +624,39 @@ status_t handle_ibex_sca(ujson_t *uj) { return handle_ibex_sca_init(uj); case kIbexScaSubcommandRFRead: return handle_ibex_sca_register_file_read(uj); + case kIbexScaSubcommandRFReadBatchRandom: + return handle_ibex_sca_register_file_read_batch_random(uj); + case kIbexScaSubcommandRFReadBatchFvsr: + return handle_ibex_sca_register_file_read_batch_fvsr(uj); case kIbexScaSubcommandRFWrite: return handle_ibex_sca_register_file_write(uj); + case kIbexScaSubcommandRFWriteBatchRandom: + return handle_ibex_sca_register_file_write_batch_random(uj); + case kIbexScaSubcommandRFWriteBatchFvsr: + return handle_ibex_sca_register_file_write_batch_fvsr(uj); case kIbexScaSubcommandTLRead: return handle_ibex_sca_tl_read(uj); + case kIbexScaSubcommandTLReadBatchRandom: + return handle_ibex_sca_tl_read_batch_random(uj); + case kIbexScaSubcommandTLReadBatchRandomFixAddress: + return handle_ibex_sca_tl_read_batch_random_fix_address(uj); + case kIbexScaSubcommandTLReadBatchFvsr: + return handle_ibex_sca_tl_read_batch_fvsr(uj); + case kIbexScaSubcommandTLReadBatchFvsrFixAddress: + return handle_ibex_sca_tl_read_batch_fvsr_fix_address(uj); case kIbexScaSubcommandTLWrite: return handle_ibex_sca_tl_write(uj); + case kIbexScaSubcommandTLWriteBatchRandom: + return handle_ibex_sca_tl_write_batch_random(uj); + case kIbexScaSubcommandTLWriteBatchRandomFixAddress: + return handle_ibex_sca_tl_write_batch_random_fix_address(uj); + case kIbexScaSubcommandTLWriteBatchFvsr: + return handle_ibex_sca_tl_write_batch_fvsr(uj); + case kIbexScaSubcommandTLWriteBatchFvsrFixAddress: + return handle_ibex_sca_tl_write_batch_fvsr_fix_address(uj); default: LOG_ERROR("Unrecognized IBEX SCA subcommand: %d", cmd); return INVALID_ARGUMENT(); } - return OK_STATUS(0); + return OK_STATUS(); } diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h index b77af6a2d43234..084ccac7cdff45 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h @@ -8,11 +8,282 @@ #include "sw/device/lib/base/status.h" #include "sw/device/lib/ujson/ujson.h" +/** + * ibex.sca.tl_write_batch_fvsr_fix_address + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration FvsR values using the software LFSR. + * - Loop num_iterations: + * - Set trigger + * - Write data over TL-UL into a single position in SRAM. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_tl_write_batch_fvsr_fix_address(ujson_t *uj); + +/** + * ibex.sca.tl_write_batch_fvsr + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration FvsR values using the software LFSR. + * - Loop num_iterations: + * - Set trigger + * - Write data over TL-UL into SRAM. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_tl_write_batch_fvsr(ujson_t *uj); + +/** + * ibex.sca.tl_write_batch_random_fix_address + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration random values using the software LFSR. + * - Loop num_iterations: + * - Set trigger + * - Write data over TL-UL into a single position in SRAM. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_tl_write_batch_random_fix_address(ujson_t *uj); + +/** + * ibex.sca.tl_write_batch_random + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration random values using the software LFSR. + * - Loop num_iterations: + * - Set trigger + * - Write data over TL-UL into SRAM. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_tl_write_batch_random(ujson_t *uj); + +/** + * ibex.sca.tl_write + * + * This SCA penetration test executes the following instructions: + * - Set trigger + * - Write data over TL-UL into SRAM. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca_tl_write(ujson_t *uj); + +/** + * ibex.sca.tl_read_batch_fvsr_fix_address + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration FvsR values using the software LFSR. + * - Set trigger + * - Read data from a single address in SRAM over TL-UL. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_tl_read_batch_fvsr_fix_address(ujson_t *uj); + +/** + * ibex.sca.tl_read_batch_fvsr + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration FvsR values using the software LFSR. + * - Set trigger + * - Read data from SRAM over TL-UL. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_tl_read_batch_fvsr(ujson_t *uj); + +/** + * ibex.sca.tl_read_batch_random_fix_address + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration random values using the software LFSR. + * - Set trigger + * - Read data from a single address in SRAM over TL-UL. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_tl_read_batch_random_fix_address(ujson_t *uj); + +/** + * ibex.sca.tl_read_batch_random + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration random values using the software LFSR. + * - Set trigger + * - Read data from SRAM over TL-UL. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_tl_read_batch_random(ujson_t *uj); + +/** + * ibex.sca.tl_read + * + * This SCA penetration test executes the following instructions: + * - Set trigger + * - Read data from SRAM over TL-UL. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca_tl_read(ujson_t *uj); + +/** + * ibex.sca.register_file_write_batch_fvsr + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration FvsR values using the software LFSR. + * - Set trigger + * - Write random data to registers in RF + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_register_file_write_batch_fvsr(ujson_t *uj); + +/** + * ibex.sca.register_file_write_batch_random + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration random values using the software LFSR. + * - Set trigger + * - Write random data to registers in RF + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_register_file_write_batch_random(ujson_t *uj); + +/** + * ibex.sca.register_file_write + * + * This SCA penetration test executes the following instructions: + * - Set trigger + * - Write provided data to registers in RF + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca_register_file_write(ujson_t *uj); + +/** + * ibex.sca.register_file_read_batch_fvsr + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration FvsR values using the software LFSR. + * - Loop num_iterations: + * - Set trigger + * - Read data from RF + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_register_file_read_batch_fvsr(ujson_t *uj); + +/** + * ibex.sca.register_file_read_batch_random + * + * This SCA penetration test executes the following instructions: + * - Generate num_iteration random values using the software LFSR. + * - Loop num_iterations: + * - Set trigger + * - Read data from RF + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_register_file_read_batch_random(ujson_t *uj); + +/** + * ibex.sca.register_file_read + * + * This SCA penetration test executes the following instructions: + * - Loop num_iterations: + * - Set trigger + * - Read data from RF + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca_register_file_read(ujson_t *uj); + +/** + * Initializes the trigger and configures the device for the Ibex SCA test. + * + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca_init(ujson_t *uj); + +/** + * Ibex SCA command handler. + * + * Command handler for the Ibex SCA command. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca(ujson_t *uj); #endif // OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_IBEX_SCA_H_ diff --git a/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h b/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h index 8c2daf1216f9f8..0bfcb272466242 100644 --- a/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h +++ b/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h @@ -23,6 +23,7 @@ extern "C" { value(_, CharUncondBranch) \ value(_, CharSramWrite) \ value(_, CharSramRead) \ + value(_, CharSramStatic) \ value(_, CharFlashWrite) \ value(_, CharFlashRead) UJSON_SERDE_ENUM(IbexFiSubcommand, ibex_fi_subcommand_t, IBEXFI_SUBCOMMAND); @@ -49,6 +50,11 @@ UJSON_SERDE_STRUCT(IbexFiLoopCounterOutput, ibex_fi_loop_counter_t, IBEXFI_LOOP_ field(err_status, uint32_t) UJSON_SERDE_STRUCT(IbexFiLoopCounterMirroredOutput, ibex_fi_loop_counter_mirrored_t, IBEXFI_LOOP_COUNTER_MIRRORED_OUTPUT); +#define IBEXFI_FAULTY_ADDRESSES(field, string) \ + field(err_status, uint32_t) \ + field(addresses, uint32_t, 8) +UJSON_SERDE_STRUCT(IbexFiFaultyAddresses, ibex_fi_faulty_addresses_t, IBEXFI_FAULTY_ADDRESSES); + // clang-format on #ifdef __cplusplus diff --git a/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h index 68736441179f18..2a0ebb1644d31b 100644 --- a/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h +++ b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h @@ -14,20 +14,40 @@ extern "C" { #define IBEXSCA_SUBCOMMAND(_, value) \ value(_, Init) \ value(_, RFRead) \ + value(_, RFReadBatchRandom) \ + value(_, RFReadBatchFvsr) \ value(_, RFWrite) \ + value(_, RFWriteBatchRandom) \ + value(_, RFWriteBatchFvsr) \ value(_, TLRead) \ - value(_, TLWrite) + value(_, TLReadBatchRandom) \ + value(_, TLReadBatchRandomFixAddress) \ + value(_, TLReadBatchFvsr) \ + value(_, TLReadBatchFvsrFixAddress) \ + value(_, TLWrite) \ + value(_, TLWriteBatchRandom) \ + value(_, TLWriteBatchRandomFixAddress) \ + value(_, TLWriteBatchFvsr) \ + value(_, TLWriteBatchFvsrFixAddress) UJSON_SERDE_ENUM(IbexScaSubcommand, ibex_sca_subcommand_t, IBEXSCA_SUBCOMMAND); #define IBEXSCA_TEST_DATA(field, string) \ - field(num_iterations, uint32_t) \ field(data, uint32_t, 8) UJSON_SERDE_STRUCT(IbexScaTestData, ibex_sca_test_data_t, IBEXSCA_TEST_DATA); +#define IBEXSCA_TEST_FVSR(field, string) \ + field(num_iterations, uint32_t) \ + field(fixed_data, uint32_t) +UJSON_SERDE_STRUCT(IbexScaTestFvsr, ibex_sca_test_fvsr_t, IBEXSCA_TEST_FVSR); + #define IBEXSCA_RESULT(field, string) \ field(result, uint32_t) UJSON_SERDE_STRUCT(IbexScaResult, ibex_sca_result_t, IBEXSCA_RESULT); +#define IBEXSCA_BATCH(field, string) \ + field(num_iterations, uint32_t) +UJSON_SERDE_STRUCT(IbexScaBatch, ibex_sca_batch_t, IBEXSCA_BATCH); + // clang-format on #ifdef __cplusplus