diff --git a/.github/workflow_metadata/pr_hash b/.github/workflow_metadata/pr_hash index 4185cfbdf..2c2f26d04 100644 --- a/.github/workflow_metadata/pr_hash +++ b/.github/workflow_metadata/pr_hash @@ -1 +1 @@ -be28f2dc551667ded53365e3fb1bc2ec38cc9ceb0797387e714aa7d37d2cc20d18c002e900a6ffedb239d00fe0bfad64 \ No newline at end of file +cffe193254f81be9b6907d79acf2c1129a0017e1762731a2d200c1de3accb97561e2bc78e3602d9867e46f390e77bb79 \ No newline at end of file diff --git a/.github/workflow_metadata/pr_timestamp b/.github/workflow_metadata/pr_timestamp index 015aac69d..2d689615c 100644 --- a/.github/workflow_metadata/pr_timestamp +++ b/.github/workflow_metadata/pr_timestamp @@ -1 +1 @@ -1744862093 \ No newline at end of file +1744901509 \ No newline at end of file diff --git a/src/integration/stimulus/L1_Nightly_Random_caliptra_ss_top_tb_regression.yml b/src/integration/stimulus/L1_Nightly_Random_caliptra_ss_top_tb_regression.yml index a8c2db005..73bfbb3d4 100644 --- a/src/integration/stimulus/L1_Nightly_Random_caliptra_ss_top_tb_regression.yml +++ b/src/integration/stimulus/L1_Nightly_Random_caliptra_ss_top_tb_regression.yml @@ -20,3 +20,5 @@ contents: $CALIPTRA_SS_ROOT/src/integration/test_suites/smoke_test_mcu_sram_execution_region/smoke_test_mcu_sram_execution_region_max_size: { weight: 100 } $CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_mcu_sram_to_sha/caliptra_ss_mcu_sram_to_sha: { weight: 100 } $CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_fuse_ctrl_external_clock/caliptra_ss_fuse_ctrl_external_clock: { weight: 100 } + $CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_lcc_escalation/caliptra_ss_lcc_escalation: { weight: 100 } + $CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_fuse_ctrl_integrity_check/caliptra_ss_fuse_ctrl_init_fail: { weight: 100 } diff --git a/src/integration/stimulus/testsuites/caliptra_ss_master_test_list.csv b/src/integration/stimulus/testsuites/caliptra_ss_master_test_list.csv index 2589dafb3..7b230043a 100644 --- a/src/integration/stimulus/testsuites/caliptra_ss_master_test_list.csv +++ b/src/integration/stimulus/testsuites/caliptra_ss_master_test_list.csv @@ -57,3 +57,4 @@ $CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_fuse_ctrl_bus_ecc_erro $CALIPTRA_SS_ROOT/src/integration/test_suites/smoke_test_wdt/smoke_test_wdt , None , None , L0 , None, caliptra_ss_top_tb, Promote , None , 100 $CALIPTRA_SS_ROOT/src/integration/test_suites/smoke_test_wdt_rst/smoke_test_wdt_rst , Directed , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100 $CALIPTRA_SS_ROOT/src/integration/test_suites/smoke_test_lcc_st_trans/smoke_test_lcc_st_trans , Directed , Nightly , L0 , L1 , caliptra_ss_top_tb, Promote , None , 100 +$CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_fuse_ctrl_integrity_check/caliptra_ss_fuse_ctrl_init_fail , Random , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100 diff --git a/src/integration/test_suites/caliptra_ss_fuse_ctrl_init_fail/caliptra_ss_fuse_ctrl_init_fail.c b/src/integration/test_suites/caliptra_ss_fuse_ctrl_init_fail/caliptra_ss_fuse_ctrl_init_fail.c new file mode 100644 index 000000000..30e76d8e8 --- /dev/null +++ b/src/integration/test_suites/caliptra_ss_fuse_ctrl_init_fail/caliptra_ss_fuse_ctrl_init_fail.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include + +#include "soc_address_map.h" +#include "printf.h" +#include "riscv_hw_if.h" +#include "soc_ifc.h" +#include "caliptra_ss_lc_ctrl_address_map.h" +#include "caliptra_ss_lib.h" +#include "fuse_ctrl.h" +#include "lc_ctrl.h" + +volatile char* stdout = (char *)SOC_MCI_TOP_MCI_REG_DEBUG_OUT; +#ifdef CPT_VERBOSITY + enum printf_verbosity verbosity_g = CPT_VERBOSITY; +#else + enum printf_verbosity verbosity_g = LOW; +#endif + +typedef struct { + uint32_t address; + uint32_t digest_address; + uint32_t index; +} partition_t; + +// XXX: Fuse addresses, eventually these should be generated automatically. +// Buffered partitions. +static partition_t partitions[8] = { + // SECRET_TEST_UNLOCK_PARTITION + { .address = 0x000, .digest_address = 0x040, .index = 0 }, + // SECRET_MANUF_PARTITION + { .address = 0x048, .digest_address = 0x088, .index = 1 }, + // SECRET_PROD_PARTITION_0 + { .address = 0x090, .digest_address = 0x098, .index = 2 }, + // SECRET_PROD_PARTITION_1 + { .address = 0x0A0, .digest_address = 0x0A8, .index = 3 }, + // SECRET_PROD_PARTITION_2 + { .address = 0x0B0, .digest_address = 0x0B8, .index = 4 }, + // SECRET_PROD_PARTITION_3 + { .address = 0x0C0, .digest_address = 0x0C8, .index = 5 }, + // SECRET_LC_TRANSITION_PARTITION + { .address = 0x4C0, .digest_address = 0x570, .index = 7 }, + // VENDOR_SECRET_PROD_PARTITION + { .address = 0x9A8, .digest_address = 0xBA8, .index = 13 } +}; + +void init_fail() { + const uint32_t faults[2] = { + CMD_FC_LCC_CORRECTABLE_FAULT, + CMD_FC_LCC_UNCORRECTABLE_FAULT + }; + + partition_t partition = partitions[xorshift32() % 8]; + uint32_t fault = faults[xorshift32() % 2]; + + if (partition.address < 0x090) { + grant_caliptra_core_for_fc_writes(); + } else { + grant_mcu_for_fc_writes(); + } + + // Write one word in the selected partition and lock it afterwards. + dai_wr(partition.address, 0x1, 0x2, 64, 0); + calculate_digest(partition.address); + + // Inject either a correctable or uncorrectable error into the written partition. + lsu_write_32(SOC_MCI_TOP_MCI_REG_DEBUG_OUT, fault); + wait_dai_op_idle(0); + + reset_fc_lcc_rtl(); + wait_dai_op_idle( + fault == CMD_FC_LCC_CORRECTABLE_FAULT ? 1 << partition.index : 0x3FFFF + ); + + uint32_t err_reg = lsu_read_32(SOC_OTP_CTRL_ERR_CODE_RF_ERR_CODE_0 + 0x4*partition.index); + uint32_t status_reg = lsu_read_32(SOC_OTP_CTRL_STATUS); + + if (fault == CMD_FC_LCC_CORRECTABLE_FAULT) { + if (err_reg != 0x2) { + VPRINTF(LOW, "ERROR: err code register does not show correctable error: %08X\n", err_reg); + return; + } + } else { + if (err_reg != 0x3) { + VPRINTF(LOW, "ERROR: err code register does not show uncorrectable error: %08X\n", err_reg); + return; + } + } +} + +void main (void) { + VPRINTF(LOW, "=================\nMCU Caliptra Boot Go\n=================\n\n") + + mcu_cptra_init_d(); + wait_dai_op_idle(0); + + lcc_initialization(); + grant_mcu_for_fc_writes(); + + transition_state(TEST_UNLOCKED0, raw_unlock_token[0], raw_unlock_token[1], raw_unlock_token[2], raw_unlock_token[3], 1); + wait_dai_op_idle(0); + + initialize_otp_controller(); + + init_fail(); + + for (uint8_t ii = 0; ii < 160; ii++) { + __asm__ volatile ("nop"); // Sleep loop as "nop" + } + + SEND_STDOUT_CTRL(0xff); +} diff --git a/src/integration/test_suites/caliptra_ss_fuse_ctrl_init_fail/caliptra_ss_fuse_ctrl_init_fail.yml b/src/integration/test_suites/caliptra_ss_fuse_ctrl_init_fail/caliptra_ss_fuse_ctrl_init_fail.yml new file mode 100644 index 000000000..667ff94e9 --- /dev/null +++ b/src/integration/test_suites/caliptra_ss_fuse_ctrl_init_fail/caliptra_ss_fuse_ctrl_init_fail.yml @@ -0,0 +1,7 @@ +--- +seed: ${PLAYBOOK_RANDOM_SEED} +testname: caliptra_ss_fuse_ctrl_init_fail +pre-exec: | + echo "Running pre_exec for [caliptra_ss_fuse_ctrl_init_fail]" + CALIPTRA_ROOT=$CALIPTRA_SS_ROOT/third_party/caliptra-rtl make -f $CALIPTRA_SS_ROOT/third_party/caliptra-rtl/tools/scripts/Makefile CALIPTRA_INTERNAL_TRNG=0 TESTNAME=smoke_test_mbox program.hex + make -f $CALIPTRA_SS_ROOT/tools/scripts/Makefile TESTNAME=caliptra_ss_fuse_ctrl_init_fail mcu_program.hex diff --git a/src/integration/test_suites/caliptra_ss_fuse_ctrl_integrity_check/caliptra_ss_fuse_ctrl_integrity_check.c b/src/integration/test_suites/caliptra_ss_fuse_ctrl_integrity_check/caliptra_ss_fuse_ctrl_integrity_check.c index 1e1e2e755..4d60f0f30 100644 --- a/src/integration/test_suites/caliptra_ss_fuse_ctrl_integrity_check/caliptra_ss_fuse_ctrl_integrity_check.c +++ b/src/integration/test_suites/caliptra_ss_fuse_ctrl_integrity_check/caliptra_ss_fuse_ctrl_integrity_check.c @@ -37,7 +37,7 @@ void main (void) { initialize_otp_controller(); - wait_dai_op_idle(0x1BFFFF); + wait_dai_op_idle(0x3FFFF); for (uint8_t ii = 0; ii < 160; ii++) { __asm__ volatile ("nop"); // Sleep loop as "nop" diff --git a/src/integration/test_suites/libs/caliptra_ss_lib/caliptra_ss_lib.h b/src/integration/test_suites/libs/caliptra_ss_lib/caliptra_ss_lib.h index 76cf8ae60..55f05e2d2 100644 --- a/src/integration/test_suites/libs/caliptra_ss_lib/caliptra_ss_lib.h +++ b/src/integration/test_suites/libs/caliptra_ss_lib/caliptra_ss_lib.h @@ -45,6 +45,8 @@ #define CMD_LC_TRIGGER_ESCALATION1 FC_LCC_CMD_OFFSET + 0x13 #define CMD_LC_DISABLE_SVA FC_LCC_CMD_OFFSET + 0x14 #define CMD_LC_ENABLE_SVA FC_LCC_CMD_OFFSET + 0x15 +#define CMD_FC_LCC_CORRECTABLE_FAULT FC_LCC_CMD_OFFSET + 0x16 +#define CMD_FC_LCC_UNCORRECTABLE_FAULT FC_LCC_CMD_OFFSET + 0x17 #define TB_CMD_DISABLE_MCU_SRAM_PROT_ASSERTS 0xC0 @@ -224,6 +226,28 @@ static inline void mcu_mbox_write_cmd_status(uint32_t mbox_num, enum mcu_mbox_cm lsu_write_32(SOC_MCI_TOP_MCU_MBOX0_CSR_MBOX_CMD_STATUS + MCU_MBOX_NUM_STRIDE * mbox_num, (cmd_status & MCU_MBOX0_CSR_MBOX_CMD_STATUS_STATUS_MASK)); } +#define FC_LCC_CMD_OFFSET 0x90 +#define CMD_FC_LCC_RESET FC_LCC_CMD_OFFSET + 0x02 +#define CMD_FORCE_FC_AWUSER_CPTR_CORE FC_LCC_CMD_OFFSET + 0x03 +#define CMD_FORCE_FC_AWUSER_MCU FC_LCC_CMD_OFFSET + 0x04 +#define CMD_RELEASE_AWUSER FC_LCC_CMD_OFFSET + 0x05 +#define CMD_FC_FORCE_ZEROIZATION FC_LCC_CMD_OFFSET + 0x06 +#define CMD_FC_FORCE_ZEROIZATION_RESET FC_LCC_CMD_OFFSET + 0x07 +#define CMD_RELEASE_ZEROIZATION FC_LCC_CMD_OFFSET + 0x08 +#define CMD_FORCE_LC_TOKENS FC_LCC_CMD_OFFSET + 0x09 +#define CMD_LC_FORCE_RMA_SCRAP_PPD FC_LCC_CMD_OFFSET + 0x0a +#define CMD_FC_TRIGGER_ESCALATION FC_LCC_CMD_OFFSET + 0x0b +#define CMD_FC_LCC_EXT_CLK_500MHZ FC_LCC_CMD_OFFSET + 0x0c +#define CMD_FC_LCC_EXT_CLK_160MHZ FC_LCC_CMD_OFFSET + 0x0d +#define CMD_FC_LCC_EXT_CLK_400MHZ FC_LCC_CMD_OFFSET + 0x0e +#define CMD_FC_LCC_EXT_CLK_1000MHZ FC_LCC_CMD_OFFSET + 0x0f +#define CMD_FC_LCC_FAULT_DIGEST FC_LCC_CMD_OFFSET + 0x10 +#define CMD_FC_LCC_FAULT_BUS_ECC FC_LCC_CMD_OFFSET + 0x11 +#define CMD_LC_TRIGGER_ESCALATION0 FC_LCC_CMD_OFFSET + 0x12 +#define CMD_LC_TRIGGER_ESCALATION1 FC_LCC_CMD_OFFSET + 0x13 +#define CMD_FC_LCC_CORRECTABLE_FAULT FC_LCC_CMD_OFFSET + 0x14 +#define CMD_FC_LCC_UNCORRECTABLE_FAULT FC_LCC_CMD_OFFSET + 0x15 + static inline uint32_t mcu_mbox_read_cmd_status(uint32_t mbox_num) { uint32_t rd_data = lsu_read_32(SOC_MCI_TOP_MCU_MBOX0_CSR_MBOX_CMD_STATUS + MCU_MBOX_NUM_STRIDE * mbox_num); VPRINTF(LOW, "MCU: Mbox%x Reading CMD_STATUS: 0x%x\n", mbox_num, rd_data); diff --git a/src/integration/test_suites/libs/fuse_ctrl/fuse_ctrl.c b/src/integration/test_suites/libs/fuse_ctrl/fuse_ctrl.c index 2431c55c4..ce3c89985 100644 --- a/src/integration/test_suites/libs/fuse_ctrl/fuse_ctrl.c +++ b/src/integration/test_suites/libs/fuse_ctrl/fuse_ctrl.c @@ -49,13 +49,12 @@ void wait_dai_op_idle(uint32_t status_mask) { status = lsu_read_32(SOC_OTP_CTRL_STATUS); dai_idle = (status >> OTP_CTRL_STATUS_DAI_IDLE_LOW) & 0x1; check_pending = (status >> OTP_CTRL_STATUS_CHECK_PENDING_LOW) & 0x1; - } while ((!dai_idle || check_pending) && (status != 0x1BFFFF)); + } while ((!dai_idle || check_pending) && ((status & 0x3FFFF) != 0x3FFFF)); // Clear the IDLE bit from the status value status &= ((((uint32_t)1) << (OTP_CTRL_STATUS_DAI_IDLE_LOW - 1)) - 1); if (status != status_mask) { VPRINTF(LOW, "ERROR: unexpected status: expected: %08X actual: %08X\n", status_mask, status); - exit(1); } VPRINTF(LOW, "DEBUG: DAI is now idle.\n"); return; diff --git a/src/integration/testbench/caliptra_ss_tb_cmd_list.svh b/src/integration/testbench/caliptra_ss_tb_cmd_list.svh index 541d58e03..a3e11585c 100644 --- a/src/integration/testbench/caliptra_ss_tb_cmd_list.svh +++ b/src/integration/testbench/caliptra_ss_tb_cmd_list.svh @@ -83,6 +83,9 @@ localparam CMD_LC_TRIGGER_ESCALATION0 = FC_LCC_CMD_OFFSET + 8'h12; localparam CMD_LC_TRIGGER_ESCALATION1 = FC_LCC_CMD_OFFSET + 8'h13; localparam CMD_LC_DISABLE_SVA = FC_LCC_CMD_OFFSET + 8'h14; localparam CMD_LC_ENABLE_SVA = FC_LCC_CMD_OFFSET + 8'h15; +localparam CMD_FC_LCC_CORRECTABLE_FAULT = FC_LCC_CMD_OFFSET + 8'h16; +localparam CMD_FC_LCC_UNCORRECTABLE_FAULT = FC_LCC_CMD_OFFSET + 8'h17; + localparam TB_DISABLE_MCU_SRAM_PROT_ASSERTS = 8'hc0; diff --git a/src/integration/testbench/caliptra_ss_top_tb_path_defines.svh b/src/integration/testbench/caliptra_ss_top_tb_path_defines.svh index b01ae69b2..880b80997 100644 --- a/src/integration/testbench/caliptra_ss_top_tb_path_defines.svh +++ b/src/integration/testbench/caliptra_ss_top_tb_path_defines.svh @@ -37,6 +37,9 @@ `ifndef FC_PATH `define FC_PATH `CPTRA_SS_TOP_PATH.u_otp_ctrl `endif + `ifndef FC_MEM + `define FC_MEM `CPTRA_SS_TB_TOP_NAME.u_otp.u_prim_ram_1p_adv.u_mem.mem + `endif `ifndef CPTRA_CORE_TOP_PATH `define CPTRA_CORE_TOP_PATH `CPTRA_SS_TOP_PATH.caliptra_top_dut `endif diff --git a/src/integration/testbench/fc_lcc_tb_services.sv b/src/integration/testbench/fc_lcc_tb_services.sv index e252cb769..4b1d267b0 100644 --- a/src/integration/testbench/fc_lcc_tb_services.sv +++ b/src/integration/testbench/fc_lcc_tb_services.sv @@ -232,5 +232,57 @@ module fc_lcc_tb_services ( end end + //------------------------------------------------------------------------- + // OTP memory fault injection + // Correctable error: One bit flip in locked partition + // Uncorrectable error: Flip all bits of a word in a locked partition + //------------------------------------------------------------------------- + + reg fault_active_q; + reg [15:0] faulted_word_q [0:7]; + + localparam int partition_offsets [0:7] = '{'h000, 'h024, 'h048, 'h050, 'h058, 'h060, 'h260, 'h4D4}; + localparam int partition_digests [0:7] = '{'h020, 'h044, 'h04C, 'h054, 'h05C, 'h064, 'h2B8, 'h5D4}; + + always_ff @(posedge clk or negedge cptra_rst_b) begin + if (!cptra_rst_b) begin + fault_active_q <= 1'b0; + end else begin + if (tb_service_cmd_valid && (tb_service_cmd == CMD_FC_LCC_CORRECTABLE_FAULT || tb_service_cmd == CMD_FC_LCC_UNCORRECTABLE_FAULT) && !fault_active_q) begin + fault_active_q <= 1'b1; + end + end + end + + generate + for (genvar i = 0; i < 8; i++) begin + always_ff @(posedge clk or negedge cptra_rst_b) begin + if (!cptra_rst_b) begin + faulted_word_q[i] <= '0; + end else begin + if (tb_service_cmd_valid && !fault_active_q) begin + // Only inject faults into partitions that are locked. + if (tb_service_cmd == CMD_FC_LCC_CORRECTABLE_FAULT) begin + faulted_word_q[i] <= { `FC_MEM[partition_offsets[i]][15:1], `FC_MEM[partition_offsets[i]][0] ^ |`FC_MEM[partition_digests[i]] }; + end else if (tb_service_cmd == CMD_FC_LCC_UNCORRECTABLE_FAULT) begin + faulted_word_q[i] <= `FC_MEM[partition_offsets[i]][15:0] ^ {16{|`FC_MEM[partition_digests[i]]}}; + end + end + end + end + end + endgenerate + + generate + for (genvar i = 0; i < 8; i++) begin + always_comb begin + if (fault_active_q) begin + force `FC_MEM[partition_offsets[i]][15:0] = faulted_word_q[i]; + end else begin + release `FC_MEM[partition_offsets[i]][15:0]; + end + end + end + endgenerate endmodule