diff --git a/sw/device/tests/crypto/cryptotest/firmware/BUILD b/sw/device/tests/crypto/cryptotest/firmware/BUILD index b6e126dc6d04bb..5b1410145cac7e 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/BUILD +++ b/sw/device/tests/crypto/cryptotest/firmware/BUILD @@ -168,12 +168,13 @@ cc_library( cc_library( name = "ibex_fi", - srcs = ["ibex_fi.c"], - hdrs = [ - "ibex_fi.h", - "status.h", + srcs = [ + "ibex_fi.S", + "ibex_fi.c", ], + hdrs = ["ibex_fi.h"], deps = [ + "//sw/device/lib/base:csr", "//sw/device/lib/base:memory", "//sw/device/lib/base:status", "//sw/device/lib/dif:flash_ctrl", @@ -191,14 +192,14 @@ 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/dif:keymgr", + "//sw/device/lib/dif:kmac", "//sw/device/lib/runtime:log", + "//sw/device/lib/testing:keymgr_testutils", "//sw/device/lib/testing/test_framework:ujson_ottf", "//sw/device/lib/ujson", "//sw/device/sca/lib:sca", diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.S b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.S new file mode 100644 index 00000000000000..64db887d95931d --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.S @@ -0,0 +1,234 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Increments a value 100 times by 1. + * + * As this function is targeted by fault injection, the code is unrolled. + * + * @param a0 initial value which gets incremented. + * @return Initial value incremeted 100 times by 1. + */ + .globl increment_100x1 + .type increment_100x1, @function + .balign 256 +increment_100x1: + // a0: init value + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + ret + + +/** + * Increments a value 100 times by 10. + * + * As this function is targeted by fault injection, the code is unrolled. + * + * @param a0 initial value which gets incremented. + * @return Initial value incremeted 100 times by 10. + */ + .globl increment_100x10 + .type increment_100x10, @function + .balign 256 +increment_100x10: + // a0: init value + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + ret diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c index ae60d3aedd7071..8b4b5e8c04c770 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c @@ -4,6 +4,8 @@ #include "sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h" +#include "sw/device/lib/base/csr.h" +#include "sw/device/lib/base/csr_registers.h" #include "sw/device/lib/base/memory.h" #include "sw/device/lib/base/status.h" #include "sw/device/lib/dif/dif_flash_ctrl.h" @@ -15,11 +17,20 @@ #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" +// A function which takes an uint32_t as its only argument. +typedef uint32_t (*str_fn_t)(uint32_t); + +extern uint32_t increment_100x10(uint32_t start_value); + +extern uint32_t increment_100x1(uint32_t start_value); + +static str_fn_t increment_100x10_remapped = (str_fn_t)increment_100x10; +static str_fn_t increment_100x1_remapped = (str_fn_t)increment_100x1; + // Make sure that this function does not get optimized by the compiler. uint32_t increment_counter(uint32_t counter) __attribute__((optnone)) { uint32_t return_value = counter + 1; @@ -90,27 +101,239 @@ static dif_flash_ctrl_device_info_t flash_info; OT_SECTION(".data") static volatile uint32_t sram_main_buffer[32]; -/** - * 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_address_translation(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)); + + // Create translation descriptions. + dif_rv_core_ibex_addr_translation_mapping_t increment_100x10_mapping = { + .matching_addr = (uintptr_t)increment_100x1, + .remap_addr = (uintptr_t)increment_100x10, + .size = 256, + }; + dif_rv_core_ibex_addr_translation_mapping_t increment_100x1_mapping = { + .matching_addr = (uintptr_t)increment_100x10, + .remap_addr = (uintptr_t)increment_100x1, + .size = 256, + }; + + // Configure slot 0 for the increment_100x10. + TRY(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationIBus, increment_100x10_mapping)); + TRY(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationDBus, increment_100x10_mapping)); + + // Configure slot 1 for the increment_100x1. + TRY(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationIBus, increment_100x1_mapping)); + TRY(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationDBus, increment_100x1_mapping)); + + // Enable the slots. + TRY(dif_rv_core_ibex_enable_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationIBus)); + TRY(dif_rv_core_ibex_enable_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationDBus)); + + TRY(dif_rv_core_ibex_enable_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationIBus)); + TRY(dif_rv_core_ibex_enable_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationDBus)); + + // FI code target. + uint32_t result_expected = 0; + sca_set_trigger_high(); + asm volatile(NOP100); + result_expected = increment_100x10_remapped(0); + sca_set_trigger_low(); + uint32_t result_target = increment_100x1_remapped(0); + // Compare values + uint32_t res = 0; + if (result_expected != 100) { + res = 1; + } + + if (result_target != 1000) { + res |= 1; + } + + // 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. + ibex_fi_test_result_t uj_output; + uj_output.result = res; + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_fi_address_translation_config(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)); + + // Address translation configuration. + dif_rv_core_ibex_addr_translation_mapping_t mapping1 = { + .matching_addr = 0xa0000000, + .remap_addr = (uintptr_t)handle_ibex_fi_address_translation_config, + .size = 256, + }; + + dif_rv_core_ibex_addr_translation_mapping_t mapping2 = { + .matching_addr = 0xa0000000, + .remap_addr = (uintptr_t)handle_ibex_fi_address_translation_config, + .size = 256, + }; + + // Write address translation configuration. + TRY(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationIBus, mapping1)); + + // FI code target. + // Either slot 0 config, which is already written, or slot 1 config, which + // gets written is targeted using FI. + sca_set_trigger_high(); + TRY(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationDBus, mapping2)); + asm volatile(NOP1000); + sca_set_trigger_low(); + + // Read back address translation configuration. + dif_rv_core_ibex_addr_translation_mapping_t mapping1_read_back; + dif_rv_core_ibex_addr_translation_mapping_t mapping2_read_back; + TRY(dif_rv_core_ibex_read_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationIBus, &mapping1_read_back)); + TRY(dif_rv_core_ibex_read_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationDBus, &mapping2_read_back)); + + uint32_t res = 0; + // Compare mapping 1. + if ((mapping1_read_back.matching_addr != mapping1.matching_addr) || + (mapping1_read_back.remap_addr != mapping1.remap_addr) || + (mapping1_read_back.size != mapping1.size)) { + res = 1; + } + + // Compare mapping 2. + if ((mapping2_read_back.matching_addr != mapping2.matching_addr) || + (mapping2_read_back.remap_addr != mapping2.remap_addr) || + (mapping2_read_back.size != mapping2.size)) { + res = 1; + } + + // 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. + ibex_fi_test_result_t uj_output; + uj_output.result = res; + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_fi_char_csr_write(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)); + + // FI code target. + sca_set_trigger_high(); + asm volatile(NOP10); + for (int i = 0; i < 100; i++) { + CSR_WRITE(CSR_REG_MSCRATCH, ref_values[0]); + } + asm volatile(NOP10); + sca_set_trigger_low(); + + uint32_t res_values; + // Read values from CSRs. + CSR_READ(CSR_REG_MSCRATCH, &res_values); + + // Compare against reference values. + uint32_t res = 0; + if (res_values != ref_values[0]) { + res = 1; + } + + // 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. + ibex_fi_test_result_t uj_output; + uj_output.result = res; + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); + return OK_STATUS(); +} + +status_t handle_ibex_fi_char_csr_read(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)); + + // Write reference value into CSR. + CSR_WRITE(CSR_REG_MSCRATCH, ref_values[0]); + + uint32_t res_values[32]; + // FI code target. + sca_set_trigger_high(); + asm volatile(NOP10); + for (int i = 0; i < 32; i++) { + CSR_READ(CSR_REG_MSCRATCH, &res_values[i]); + } + asm volatile(NOP10); + sca_set_trigger_low(); + + // Compare against reference values. + uint32_t res = 0; + for (int i = 0; i < 32; i++) { + if (res_values[i] != ref_values[0]) { + res |= 1; + } + } + + // 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. + ibex_fi_test_result_t uj_output; + uj_output.result = res; + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); + return OK_STATUS(); +} + 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 +352,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 +368,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,36 +391,20 @@ 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; uj_output.result = res; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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 +420,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 +438,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,37 +456,20 @@ 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; uj_output.result = res; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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_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,36 +503,20 @@ 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; uj_output.result = res; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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,34 +546,20 @@ 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; uj_output.result = res; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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,34 +671,20 @@ 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; uj_output.result = result; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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 +704,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; @@ -570,31 +712,13 @@ status_t handle_ibex_fi_char_conditional_branch(ujson_t *uj) { uj_output.result2 = branch_else; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_test_result_mult_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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 +735,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; @@ -619,28 +743,13 @@ status_t handle_ibex_fi_char_mem_op_loop(ujson_t *uj) { uj_output.loop_counter2 = loop_counter2; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_loop_counter_mirrored_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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,34 +771,20 @@ 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; uj_output.loop_counter = loop_counter; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_loop_counter_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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 +805,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; @@ -718,27 +813,13 @@ status_t handle_ibex_fi_char_reg_op_loop(ujson_t *uj) { uj_output.loop_counter2 = loop_counter2; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_loop_counter_mirrored_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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,33 +843,20 @@ 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; uj_output.loop_counter = loop_counter; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_loop_counter_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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,33 +896,20 @@ 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; uj_output.result = res; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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,22 +946,16 @@ 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; uj_output.result = res; uj_output.err_status = codes; RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); - return OK_STATUS(0); + return OK_STATUS(); } -/** - * 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 +967,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); + return OK_STATUS(); } -/** - * 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)); @@ -962,9 +1004,17 @@ status_t handle_ibex_fi(ujson_t *uj) { return handle_ibex_fi_char_flash_write(uj); case kIbexFiSubcommandCharFlashRead: return handle_ibex_fi_char_flash_read(uj); + case kIbexFiSubcommandCharCsrWrite: + return handle_ibex_fi_char_csr_write(uj); + case kIbexFiSubcommandCharCsrRead: + return handle_ibex_fi_char_csr_read(uj); + case kIbexFiSubcommandAddressTranslationCfg: + return handle_ibex_fi_address_translation_config(uj); + case kIbexFiSubcommandAddressTranslation: + return handle_ibex_fi_address_translation(uj); default: LOG_ERROR("Unrecognized IBEX FI subcommand: %d", cmd); return INVALID_ARGUMENT(); } - return OK_STATUS(0); + return OK_STATUS(); } diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h index 2e9f8d795b671c..116b78eb34e437 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h @@ -8,19 +8,322 @@ #include "sw/device/lib/base/status.h" #include "sw/device/lib/ujson/ujson.h" +/** + * ibex.fi.address_translation command handler. + * + * This FI penetration tests executes the following instructions: + * - Configure the address translation for slot 0 and 1. + * - increment_100x1 gets remapped to increment_100x10 and + * increment_100x10 gets remapped to increment_100x1 using the address + * translation unit + * - Set the trigger. + * - Add 100 NOPs to delay the trigger. + * - Execute the increment_100x10 function. + * - Unset the trigger. + * - Check if instead of the expected function the target function was called. + * - 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_address_translation(ujson_t *uj); + +/** + * ibex.fi.address_translation_config command handler. + * + * This FI penetration tests executes the following instructions: + * - Configure the address translation for DMEM and IMEM. + * - Set the trigger. + * - Add 1000 NOPs. + * - Unset the trigger. + * - Read address translation config. + * - 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_address_translation_config(ujson_t *uj); + +/** + * ibex.fi.char.csr_write command handler. + * + * This FI penetration tests executes the following instructions: + * - Set the trigger. + * - Add 10 NOPs to delay the trigger + * - Write reference values into CSR. + * - Unset the trigger. + * - Read value from CSR. + * - 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_csr_write(ujson_t *uj); + +/** + * ibex.fi.char.csr_read command handler. + * + * This FI penetration tests executes the following instructions: + * - Write reference values into CSRs. + * - Set the trigger. + * - Add 10 NOPs to delay the trigger + * - Read values from CSRs. + * - 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_csr_read(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_flash_read(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_flash_write(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_sram_read(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_sram_write(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_unconditional_branch(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_conditional_branch(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_mem_op_loop(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_reg_op_loop(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_fi_char_unrolled_mem_op_loop(ujson_t *uj); + +/** + * 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 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.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.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..0e9927f1bb244e 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c @@ -6,36 +6,69 @@ #include "sw/device/lib/base/memory.h" #include "sw/device/lib/base/status.h" +#include "sw/device/lib/dif/dif_keymgr.h" +#include "sw/device/lib/dif/dif_kmac.h" #include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/keymgr_testutils.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/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" +static dif_keymgr_t keymgr; +static dif_kmac_t kmac; + // 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]; -/** - * 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_key_sideloading(ujson_t *uj) { + ibex_sca_salt_t uj_data; + TRY(ujson_deserialize_ibex_sca_salt_t(uj, &uj_data)); + + // Initialize keymgr and advance to CreatorRootKey state. + TRY(keymgr_testutils_startup(&keymgr, &kmac)); + + // Generate identity at CreatorRootKey (to follow same sequence and reuse + // chip_sw_keymgr_key_derivation_vseq.sv). + TRY(keymgr_testutils_generate_identity(&keymgr)); + + // Advance to OwnerIntermediateKey state. + TRY(keymgr_testutils_advance_state(&keymgr, &kOwnerIntParams)); + TRY(keymgr_testutils_check_state(&keymgr, + kDifKeymgrStateOwnerIntermediateKey)); + + // Set the salt based on the input. + dif_keymgr_versioned_key_params_t sideload_params = kKeyVersionedParams; + for (int i = 0; i < 8; i++) { + sideload_params.salt[i] = uj_data.salt[i]; + } + + // Trigger keymanager to create a new key based on the provided salt. + sca_set_trigger_high(); + TRY(keymgr_testutils_generate_versioned_key(&keymgr, sideload_params)); + sca_set_trigger_low(); + + // Read back generated key provided at the software interface. + dif_keymgr_output_t key; + TRY(dif_keymgr_read_output(&keymgr, &key)); + + // Acknowledge test. + ibex_sca_key_t uj_key; + for (int i = 0; i < 8; i++) { + uj_key.share0[i] = key.value[0][i]; + uj_key.share1[i] = key.value[1][i]; + } + RESP_OK(ujson_serialize_ibex_sca_key_t, uj, &uj_key); + return OK_STATUS(); +} + status_t handle_ibex_sca_tl_write(ujson_t *uj) { // Get data to write into SRAM. ibex_sca_test_data_t uj_data; @@ -61,22 +94,9 @@ status_t handle_ibex_sca_tl_write(ujson_t *uj) { 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(); } -/** - * 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. - */ status_t handle_ibex_sca_tl_read(ujson_t *uj) { // Get data to write into SRAM. ibex_sca_test_data_t uj_data; @@ -109,22 +129,9 @@ status_t handle_ibex_sca_tl_read(ujson_t *uj) { 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(); } -/** - * 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. - */ status_t handle_ibex_sca_register_file_write(ujson_t *uj) { // Get data to write into RF. ibex_sca_test_data_t uj_data; @@ -146,22 +153,9 @@ status_t handle_ibex_sca_register_file_write(ujson_t *uj) { 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(); } -/** - * 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. - */ status_t handle_ibex_sca_register_file_read(ujson_t *uj) { // Get data to write into RF. ibex_sca_test_data_t uj_data; @@ -187,35 +181,22 @@ status_t handle_ibex_sca_register_file_read(ujson_t *uj) { 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); // As we are using the software defined trigger, the first argument of // sca_init is not needed. kScaTriggerSourceAes is selected as a placeholder. - sca_init(kScaTriggerSourceAes, kScaPeripheralIoDiv4); + sca_init(kScaTriggerSourceAes, kScaPeripheralIoDiv4 | kScaPeripheralKmac); // 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)); @@ -230,9 +211,11 @@ status_t handle_ibex_sca(ujson_t *uj) { return handle_ibex_sca_tl_read(uj); case kIbexScaSubcommandTLWrite: return handle_ibex_sca_tl_write(uj); + case kIbexScaSubcommandKeySideloading: + return handle_ibex_sca_key_sideloading(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..221c04fc70756a 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h @@ -8,11 +8,104 @@ #include "sw/device/lib/base/status.h" #include "sw/device/lib/ujson/ujson.h" +/** + * ibex.sca.key_sideloading + * + * This SCA penetration test executes the following instructions: + * - Retrieve salt over UART & feed salt into keymanager + * - Set trigger + * - Instruct the keymanager to generate a key based on the salt. + * - Unset trigger + * - Read back generated key provided at the SW interface of the keymanager. + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj An initialized uJSON context. + * @return OK or error. + */ +status_t handle_ibex_sca_key_sideloading(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca_tl_write(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca_tl_read(ujson_t *uj); + +/** + * 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 An initialized uJSON context. + * @return OK or error. + */ status_t handle_ibex_sca_register_file_write(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..c3b6e8d377f8b0 100644 --- a/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h +++ b/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h @@ -24,7 +24,11 @@ extern "C" { value(_, CharSramWrite) \ value(_, CharSramRead) \ value(_, CharFlashWrite) \ - value(_, CharFlashRead) + value(_, CharFlashRead) \ + value(_, CharCsrRead) \ + value(_, CharCsrWrite) \ + value(_, AddressTranslationCfg) \ + value(_, AddressTranslation) UJSON_SERDE_ENUM(IbexFiSubcommand, ibex_fi_subcommand_t, IBEXFI_SUBCOMMAND); #define IBEXFI_TEST_RESULT(field, string) \ 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..74ca1a363d28c7 100644 --- a/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h +++ b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h @@ -16,7 +16,8 @@ extern "C" { value(_, RFRead) \ value(_, RFWrite) \ value(_, TLRead) \ - value(_, TLWrite) + value(_, TLWrite) \ + value(_, KeySideloading) UJSON_SERDE_ENUM(IbexScaSubcommand, ibex_sca_subcommand_t, IBEXSCA_SUBCOMMAND); #define IBEXSCA_TEST_DATA(field, string) \ @@ -24,6 +25,15 @@ UJSON_SERDE_ENUM(IbexScaSubcommand, ibex_sca_subcommand_t, IBEXSCA_SUBCOMMAND); field(data, uint32_t, 8) UJSON_SERDE_STRUCT(IbexScaTestData, ibex_sca_test_data_t, IBEXSCA_TEST_DATA); +#define IBEXSCA_SALT(field, string) \ + field(salt, uint32_t, 8) +UJSON_SERDE_STRUCT(IbexScaSalt, ibex_sca_salt_t, IBEXSCA_SALT); + +#define IBEXSCA_KEY(field, string) \ + field(share0, uint32_t, 8) \ + field(share1, uint32_t, 8) +UJSON_SERDE_STRUCT(IbexScaKey, ibex_sca_key_t, IBEXSCA_KEY); + #define IBEXSCA_RESULT(field, string) \ field(result, uint32_t) UJSON_SERDE_STRUCT(IbexScaResult, ibex_sca_result_t, IBEXSCA_RESULT);