Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflow_metadata/pr_hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
be28f2dc551667ded53365e3fb1bc2ec38cc9ceb0797387e714aa7d37d2cc20d18c002e900a6ffedb239d00fe0bfad64
cffe193254f81be9b6907d79acf2c1129a0017e1762731a2d200c1de3accb97561e2bc78e3602d9867e46f390e77bb79
2 changes: 1 addition & 1 deletion .github/workflow_metadata/pr_timestamp
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1744862093
1744901509
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <stdlib.h>

#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);
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
24 changes: 24 additions & 0 deletions src/integration/test_suites/libs/caliptra_ss_lib/caliptra_ss_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions src/integration/test_suites/libs/fuse_ctrl/fuse_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/integration/testbench/caliptra_ss_tb_cmd_list.svh
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 3 additions & 0 deletions src/integration/testbench/caliptra_ss_top_tb_path_defines.svh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 52 additions & 0 deletions src/integration/testbench/fc_lcc_tb_services.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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