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
8 changes: 4 additions & 4 deletions docs/testplan.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ Perform a write through the MCI SRAM controller, followed by the double ECC erro
Test should result in ECC error being raised and data inside SRAM should not be modified.
'''
stage: ""
tests: []
tests: [mci_sram_error]
}
{
name: mci_trace_buffer_axi_access
Expand All @@ -382,7 +382,7 @@ Inject invalid state into `otp_static_state` and verify that caliptra-ss becomes
Release error injection and check that caliptra-ss is once more in unlocked state.
'''
stage: ""
tests: []
tests: [mci_lcc_state_error]
}
{
name: mci_lcc_state_error_to_locked
Expand All @@ -393,7 +393,7 @@ Request scrap transition or inject state_error, release error injection and chec
caliptra-ss is no longer unlocked and in the `DEVICE_PRODUCTION`.
'''
stage: ""
tests: []
tests: [mci_lcc_state_error_to_locked]
}
{
name: mci_lcc_manuf_to_non_debug
Expand All @@ -408,7 +408,7 @@ Either issue a SCRAP request or inject a state error, then verify that device li
name: mci_lcc_no_zeroization
desc: "Set one of the `cptra_ss_FIPS_ZEROIZATION_PPD_i` or `ss_soc_MCU_ROM_zeroization_mask_reg` and make sure that OTP was not zeroized."
stage: ""
tests: []
tests: [mci_lcc_no_zeroization]
}
{
name: mci_read_all_regs_test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,7 @@ $CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_lcc_volatile_unlock_wr
$CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_fuse_ctrl_registers/caliptra_ss_fuse_ctrl_registers , Directed , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100
$CALIPTRA_SS_ROOT/src/integration/test_suites/caliptra_ss_lcc_otp_prog_error/caliptra_ss_lcc_otp_prog_error , Random , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100
$CALIPTRA_SS_ROOT/src/integration/test_suites/smoke_test_fc_secret_prog_in_dbg/smoke_test_fc_secret_prog_in_dbg , Directed , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100
$CALIPTRA_SS_ROOT/src/integration/test_suites/mci_lcc_state_error/mci_lcc_state_error , Directed , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100
$CALIPTRA_SS_ROOT/src/integration/test_suites/mci_sram_error/mci_sram_error , Directed , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100
$CALIPTRA_SS_ROOT/src/integration/test_suites/mci_lcc_no_zeroization/mci_lcc_no_zeroization , Directed , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100
$CALIPTRA_SS_ROOT/src/integration/test_suites/mci_lcc_state_error_to_locked/mci_lcc_state_error_to_locked , Directed , Nightly , None, L1 , caliptra_ss_top_tb, None , None , 100
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@
#define CMD_LC_TRIGGER_ESCALATION1_DIS FC_LCC_CMD_OFFSET + 0x1C
#define CMD_LC_KMAC_ERR_INJECTION FC_LCC_CMD_OFFSET + 0x1D
#define CMD_LC_KMAC_ERR_INJECTION_DIS FC_LCC_CMD_OFFSET + 0x1E
#define CMD_MCI_INJECT_STATE_ERROR FC_LCC_CMD_OFFSET + 0x1F
#define CMD_MCI_RELEASE_STATE_ERROR FC_LCC_CMD_OFFSET + 0x20
#define CMD_MCI_SRAM_DMI_ACCESS FC_LCC_CMD_OFFSET + 0x21
#define CMD_MCI_SRAM_DMI_ACCESS_DIS FC_LCC_CMD_OFFSET + 0x22


#define TB_CMD_DISABLE_MCU_SRAM_PROT_ASSERTS 0xC0

#define TB_CMD_DISABLE_INJECT_ECC_ERROR 0xe0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//********************************************************************************
//
// Test: mci_lcc_no_zeroization
//
// Verifies that zeroization does NOT trigger when PPD stays 0, regardless of
// the ss_soc_MCU_ROM_zeroization_mask_reg value (FC_FIPS_ZEROZATION register).
//
// FIPS_ZEROIZATION_CMD_o = (&ss_soc_MCU_ROM_zeroization_mask_reg) & FIPS_ZEROIZATION_PPD_i
//
// With PPD=0, the AND result is 0 in both paths tested:
// FIPS-mask path: random non-zero value written to FC_FIPS_ZEROZATION, PPD=0
// PPD path: zero written to FC_FIPS_ZEROZATION, PPD=0
// The path is selected randomly each run via xorshift32.
// The test confirms this by verifying debug_locked remains 0 after the write.
//
//********************************************************************************
#include <stdint.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

void main(void) {
VPRINTF(LOW, "=================\nMCU mci_lcc_no_zeroization\n=================\n\n");

mcu_cptra_init_d();
wait_dai_op_idle(0);

lcc_initialization();
grant_mcu_for_fc_writes();

transition_state_check(TEST_UNLOCKED0, raw_unlock_token[0], raw_unlock_token[1], raw_unlock_token[2], raw_unlock_token[3], 1);

initialize_otp_controller();

// Confirm OTP broadcast is valid before the test: debug_locked should be 0.
uint32_t sec_state = lsu_read_32(SOC_MCI_TOP_MCI_REG_SECURITY_STATE);
if (sec_state & MCI_REG_SECURITY_STATE_DEBUG_LOCKED_MASK) {
VPRINTF(LOW, "ERROR: expected debug_locked=0 before zeroization mask write, got SECURITY_STATE=0x%08x\n", sec_state);
SEND_STDOUT_CTRL(0x01);
return;
}
VPRINTF(LOW, "INFO: debug_locked=0 confirmed before test (SECURITY_STATE=0x%08x)\n", sec_state);

// Randomly choose between two no-zeroization paths (PPD is always 0 in testbench).
// FIPS_ZEROIZATION_CMD_o = mask & PPD_i — with PPD=0 the result is 0 in both cases.
uint32_t rand_val = xorshift32();
uint32_t mask_val;
const char *path_name;
if (rand_val & 1) {
// FIPS-mask path: random non-zero mask, PPD=0 → cmd=0
mask_val = rand_val | 0x1;
path_name = "FIPS mask";
} else {
// PPD path: mask=0, PPD=0 → cmd=0 regardless of mask
mask_val = 0x0;
path_name = "PPD (mask=0)";
}
VPRINTF(LOW, "INFO: writing 0x%08x to FC_FIPS_ZEROZATION (%s path, PPD=0)\n", mask_val, path_name);
lsu_write_32(SOC_MCI_TOP_MCI_REG_FC_FIPS_ZEROZATION, mask_val);

// Allow a few cycles for any unintended side-effects to propagate.
for (uint8_t i = 0; i < 32; i++) {
__asm__ volatile ("nop");
}

// Verify the register was written correctly.
uint32_t mask_rb = lsu_read_32(SOC_MCI_TOP_MCI_REG_FC_FIPS_ZEROZATION);
if (mask_rb != mask_val) {
VPRINTF(LOW, "ERROR: FC_FIPS_ZEROZATION readback 0x%08x, expected 0x%08x\n", mask_rb, mask_val);
SEND_STDOUT_CTRL(0x01);
return;
}
VPRINTF(LOW, "INFO: FC_FIPS_ZEROZATION reads back 0x%08x as expected\n", mask_rb);

// Verify that OTP was NOT zeroized: debug_locked must still be 0.
sec_state = lsu_read_32(SOC_MCI_TOP_MCI_REG_SECURITY_STATE);
if (sec_state & MCI_REG_SECURITY_STATE_DEBUG_LOCKED_MASK) {
VPRINTF(LOW, "ERROR: debug_locked=1 after mask-only write — unexpected zeroization! SECURITY_STATE=0x%08x\n", sec_state);
SEND_STDOUT_CTRL(0x01);
return;
}
VPRINTF(LOW, "INFO: debug_locked=0 confirmed — OTP was NOT zeroized as expected (SECURITY_STATE=0x%08x)\n", sec_state);

// Clean up: clear the mask register.
lsu_write_32(SOC_MCI_TOP_MCI_REG_FC_FIPS_ZEROZATION, 0x0);

for (uint8_t i = 0; i < 160; i++) {
__asm__ volatile ("nop");
}

SEND_STDOUT_CTRL(0xff);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
seed: ${PLAYBOOK_RANDOM_SEED}
testname: mci_lcc_no_zeroization
pre-exec: |
echo "Running pre_exec for [mci_lcc_no_zeroization]"
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=mci_lcc_no_zeroization mcu_program.hex
118 changes: 118 additions & 0 deletions src/integration/test_suites/mci_lcc_state_error/mci_lcc_state_error.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//********************************************************************************
//
// Test: mci_lcc_state_error
//
// Verify that asserting state_error to the MCI LCC state translator while in
// an unlocked state causes the security state to transition to debug_locked.
// After releasing the error and resetting the LCC/FC/MCI, the state should
// return to debug_unlocked (TEST_UNLOCKED0 is still in OTP).
//
//********************************************************************************
#include <stdint.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

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_check(TEST_UNLOCKED0, raw_unlock_token[0], raw_unlock_token[1], raw_unlock_token[2], raw_unlock_token[3], 1);

initialize_otp_controller();

// Verify that the device starts with debug unlocked in TEST_UNLOCKED0.
uint32_t sec_state = lsu_read_32(SOC_MCI_TOP_MCI_REG_SECURITY_STATE);
if (sec_state & MCI_REG_SECURITY_STATE_DEBUG_LOCKED_MASK) {
VPRINTF(LOW, "ERROR: expected debug_locked=0 before state_error injection, got SECURITY_STATE=0x%08x\n", sec_state);
SEND_STDOUT_CTRL(0x01);
return;
}
VPRINTF(LOW, "INFO: debug_locked=0 confirmed before state_error injection (SECURITY_STATE=0x%08x)\n", sec_state);

// Force state_error high via the testbench service.
VPRINTF(LOW, "INFO: injecting state_error into MCI LCC state translator\n");
lsu_write_32(SOC_MCI_TOP_MCI_REG_DEBUG_OUT, CMD_MCI_INJECT_STATE_ERROR);

// Poll until debug_locked == 1.
uint32_t locked = 0;
for (uint32_t i = 0; i < 10000; i++) {
sec_state = lsu_read_32(SOC_MCI_TOP_MCI_REG_SECURITY_STATE);
if (sec_state & MCI_REG_SECURITY_STATE_DEBUG_LOCKED_MASK) {
locked = 1;
break;
}
}
if (!locked) {
VPRINTF(LOW, "ERROR: debug_locked did not become 1 after state_error injection (SECURITY_STATE=0x%08x)\n", sec_state);
SEND_STDOUT_CTRL(0x01);
return;
}
VPRINTF(LOW, "INFO: debug_locked=1 confirmed after state_error injection (SECURITY_STATE=0x%08x)\n", sec_state);

// Release the injected state_error.
VPRINTF(LOW, "INFO: releasing state_error injection\n");
lsu_write_32(SOC_MCI_TOP_MCI_REG_DEBUG_OUT, CMD_MCI_RELEASE_STATE_ERROR);

// Reset FC/LCC/MCI to recover the unlocked state.
// After reset the translator will re-evaluate OTP state (still TEST_UNLOCKED0)
// and return to TRANSLATOR_UNPROV_DEBUG with debug_locked=0.
reset_fc_lcc_rtl();
wait_dai_op_idle(0);
lcc_initialization();

// Poll until debug_locked == 0.
uint32_t unlocked = 0;
for (uint32_t i = 0; i < 10000; i++) {
sec_state = lsu_read_32(SOC_MCI_TOP_MCI_REG_SECURITY_STATE);
if (!(sec_state & MCI_REG_SECURITY_STATE_DEBUG_LOCKED_MASK)) {
unlocked = 1;
break;
}
}
if (!unlocked) {
VPRINTF(LOW, "ERROR: debug_locked did not return to 0 after reset (SECURITY_STATE=0x%08x)\n", sec_state);
SEND_STDOUT_CTRL(0x01);
return;
}
VPRINTF(LOW, "INFO: debug_locked=0 confirmed after reset (SECURITY_STATE=0x%08x)\n", sec_state);

for (uint8_t i = 0; i < 160; i++) {
__asm__ volatile ("nop");
}

SEND_STDOUT_CTRL(0xff);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
seed: ${PLAYBOOK_RANDOM_SEED}
testname: mci_lcc_state_error
pre-exec: |
echo "Running pre_exec for [mci_lcc_state_error]"
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=mci_lcc_state_error mcu_program.hex
Loading
Loading