diff --git a/hw/opentitan/ot_otp_dj.c b/hw/opentitan/ot_otp_dj.c index 67895f9ed903..7f2759cc2bf0 100644 --- a/hw/opentitan/ot_otp_dj.c +++ b/hw/opentitan/ot_otp_dj.c @@ -2058,6 +2058,21 @@ static int ot_otp_dj_dai_write_u64(OtOTPDjState *s, unsigned address) uint32_t lo = s->regs[R_DIRECT_ACCESS_WDATA_0]; uint32_t hi = s->regs[R_DIRECT_ACCESS_WDATA_1]; + unsigned part_ix = (unsigned)s->dai->partition; + bool is_secret = ot_otp_dj_is_secret(part_ix); + bool is_zer = ot_otp_dj_is_part_zer_offset(part_ix, address); + + if (is_secret && !is_zer) { + const uint8_t *scrambling_key = s->otp_scramble_keys[part_ix]; + uint64_t data = ((uint64_t)hi << 32u) | lo; + g_assert(scrambling_key); + OtPresentState *ps = ot_present_new(); + ot_present_init(ps, scrambling_key); + ot_present_encrypt(ps, data, &data); + lo = (uint32_t)data; + hi = (uint32_t)(data >> 32u); + } + if ((dst_lo & ~lo) || (dst_hi & ~hi)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Cannot clear OTP bits\n", __func__, s->ot_id); @@ -2486,27 +2501,31 @@ static uint64_t ot_otp_dj_reg_read(void *opaque, hwaddr addr, unsigned size) case R_DIRECT_ACCESS_RDATA_1: case R_DIRECT_ACCESS_ADDRESS: case R_VENDOR_TEST_READ_LOCK ... R_ROM_PATCH_READ_LOCK: + case R_CHECK_TRIGGER_REGWEN: + case R_CHECK_REGWEN: val32 = s->regs[reg]; break; case R_STATUS: val32 = ot_otp_dj_get_status(s); break; case R_DIRECT_ACCESS_REGWEN: - val32 = FIELD_DP32(0, DIRECT_ACCESS_REGWEN, REGWEN, - (uint32_t)!ot_otp_dj_dai_is_busy(s)); + /* disabled either if SW locked, or if DAI is busy. */ + val32 = s->regs[reg]; + val32 &= FIELD_DP32(0u, DIRECT_ACCESS_REGWEN, REGWEN, + (uint32_t)!ot_otp_dj_dai_is_busy(s)); break; /* NOLINTNEXTLINE */ case R_DIRECT_ACCESS_CMD: + case R_CHECK_TRIGGER: val32 = 0; /* R0W1C */ break; - case R_CHECK_TRIGGER_REGWEN: - case R_CHECK_TRIGGER: - case R_CHECK_REGWEN: case R_CHECK_TIMEOUT: case R_INTEGRITY_CHECK_PERIOD: case R_CONSISTENCY_CHECK_PERIOD: - /* @todo not yet implemented */ - val32 = 0; + /* @todo: not yet implemented, but these are R/W registers */ + qemu_log_mask(LOG_UNIMP, "%s: %s: %s is not supported\n", __func__, + s->ot_id, REG_NAME(reg)); + val32 = s->regs[reg]; break; case R_VENDOR_TEST_DIGEST_0 ... R_SECRET3_DIGEST_1: /* @@ -2589,7 +2608,6 @@ static void ot_otp_dj_reg_write(void *opaque, hwaddr addr, uint64_t value, break; case R_STATUS: case R_ERR_CODE_0 ... R_ERR_CODE_23: - case R_DIRECT_ACCESS_REGWEN: case R_DIRECT_ACCESS_RDATA_0: case R_DIRECT_ACCESS_RDATA_1: case R_VENDOR_TEST_DIGEST_0 ... R_SECRET3_DIGEST_1: @@ -2622,6 +2640,10 @@ static void ot_otp_dj_reg_write(void *opaque, hwaddr addr, uint64_t value, s->regs[reg] = val32; ot_otp_dj_update_alerts(s); break; + case R_DIRECT_ACCESS_REGWEN: + val32 &= R_DIRECT_ACCESS_REGWEN_REGWEN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; case R_DIRECT_ACCESS_CMD: if (FIELD_EX32(val32, DIRECT_ACCESS_CMD, RD)) { ot_otp_dj_dai_read(s); @@ -2644,8 +2666,14 @@ static void ot_otp_dj_reg_write(void *opaque, hwaddr addr, uint64_t value, s->regs[reg] &= val32; /* RW0C */ break; case R_CHECK_TRIGGER_REGWEN: - case R_CHECK_TRIGGER: + val32 &= R_CHECK_TRIGGER_REGWEN_REGWEN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; case R_CHECK_REGWEN: + val32 &= R_CHECK_REGWEN_REGWEN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; + case R_CHECK_TRIGGER: case R_CHECK_TIMEOUT: case R_INTEGRITY_CHECK_PERIOD: case R_CONSISTENCY_CHECK_PERIOD: diff --git a/hw/opentitan/ot_otp_eg.c b/hw/opentitan/ot_otp_eg.c index 99a340315321..e33913d80da0 100644 --- a/hw/opentitan/ot_otp_eg.c +++ b/hw/opentitan/ot_otp_eg.c @@ -1939,6 +1939,20 @@ static int ot_otp_eg_dai_write_u64(OtOTPEgState *s, unsigned address) uint32_t lo = s->regs[R_DIRECT_ACCESS_WDATA_0]; uint32_t hi = s->regs[R_DIRECT_ACCESS_WDATA_1]; + unsigned part_ix = (unsigned)s->dai->partition; + bool is_secret = ot_otp_eg_is_secret(part_ix); + + if (is_secret) { + const uint8_t *scrambling_key = s->otp_scramble_keys[part_ix]; + uint64_t data = ((uint64_t)hi << 32u) | lo; + g_assert(scrambling_key); + OtPresentState *ps = ot_present_new(); + ot_present_init(ps, scrambling_key); + ot_present_encrypt(ps, data, &data); + lo = (uint32_t)data; + hi = (uint32_t)(data >> 32u); + } + if ((dst_lo & ~lo) || (dst_hi & ~hi)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Cannot clear OTP bits\n", __func__, s->ot_id); @@ -2367,27 +2381,31 @@ static uint64_t ot_otp_eg_reg_read(void *opaque, hwaddr addr, unsigned size) case R_DIRECT_ACCESS_RDATA_1: case R_DIRECT_ACCESS_ADDRESS: case R_VENDOR_TEST_READ_LOCK ... R_ROT_CREATOR_AUTH_STATE_READ_LOCK: + case R_CHECK_TRIGGER_REGWEN: + case R_CHECK_REGWEN: val32 = s->regs[reg]; break; case R_STATUS: val32 = ot_otp_eg_get_status(s); break; case R_DIRECT_ACCESS_REGWEN: - val32 = FIELD_DP32(0, DIRECT_ACCESS_REGWEN, REGWEN, - (uint32_t)!ot_otp_eg_dai_is_busy(s)); + /* disabled either if SW locked, or if DAI is busy. */ + val32 = s->regs[reg]; + val32 &= FIELD_DP32(0u, DIRECT_ACCESS_REGWEN, REGWEN, + (uint32_t)!ot_otp_eg_dai_is_busy(s)); break; /* NOLINTNEXTLINE */ case R_DIRECT_ACCESS_CMD: + case R_CHECK_TRIGGER: val32 = 0; /* R0W1C */ break; - case R_CHECK_TRIGGER_REGWEN: - case R_CHECK_TRIGGER: - case R_CHECK_REGWEN: case R_CHECK_TIMEOUT: case R_INTEGRITY_CHECK_PERIOD: case R_CONSISTENCY_CHECK_PERIOD: - /* TODO: not yet implemented */ - val32 = 0; + /* @todo: not yet implemented, but these are R/W registers */ + qemu_log_mask(LOG_UNIMP, "%s: %s: %s is not supported\n", __func__, + s->ot_id, REG_NAME(reg)); + val32 = s->regs[reg]; break; case R_VENDOR_TEST_DIGEST_0 ... R_SECRET2_DIGEST_1: /* @@ -2470,7 +2488,6 @@ static void ot_otp_eg_reg_write(void *opaque, hwaddr addr, uint64_t value, break; case R_STATUS: case R_ERR_CODE_0 ... R_ERR_CODE_12: - case R_DIRECT_ACCESS_REGWEN: case R_DIRECT_ACCESS_RDATA_0: case R_DIRECT_ACCESS_RDATA_1: case R_VENDOR_TEST_DIGEST_0 ... R_SECRET2_DIGEST_1: @@ -2503,6 +2520,10 @@ static void ot_otp_eg_reg_write(void *opaque, hwaddr addr, uint64_t value, s->regs[reg] = val32; ot_otp_eg_update_alerts(s); break; + case R_DIRECT_ACCESS_REGWEN: + val32 &= R_DIRECT_ACCESS_REGWEN_REGWEN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; case R_DIRECT_ACCESS_CMD: if (FIELD_EX32(val32, DIRECT_ACCESS_CMD, RD)) { ot_otp_eg_dai_read(s); @@ -2525,8 +2546,14 @@ static void ot_otp_eg_reg_write(void *opaque, hwaddr addr, uint64_t value, s->regs[reg] &= val32; /* RW0C */ break; case R_CHECK_TRIGGER_REGWEN: - case R_CHECK_TRIGGER: + val32 &= R_CHECK_TRIGGER_REGWEN_REGWEN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; case R_CHECK_REGWEN: + val32 &= R_CHECK_REGWEN_REGWEN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; + case R_CHECK_TRIGGER: case R_CHECK_TIMEOUT: case R_INTEGRITY_CHECK_PERIOD: case R_CONSISTENCY_CHECK_PERIOD: diff --git a/tests/opentitan/data/earlgrey-tests.txt b/tests/opentitan/data/earlgrey-tests.txt index c39b5ae21576..23ef281e8f92 100644 --- a/tests/opentitan/data/earlgrey-tests.txt +++ b/tests/opentitan/data/earlgrey-tests.txt @@ -485,6 +485,8 @@ pass: //sw/device/tests:kmac_mode_kmac_test_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:kmac_mode_kmac_test_sim_qemu_sival_rom_ext pass: //sw/device/tests:kmac_smoketest_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:kmac_smoketest_sim_qemu_sival_rom_ext +pass: //sw/device/tests:lc_ctrl_otp_hw_cfg0_test_sim_qemu_rom_with_fake_keys +pass: //sw/device/tests:lc_ctrl_otp_hw_cfg0_test_sim_qemu_sival_rom_ext pass: //sw/device/tests:otbn_ecdsa_op_irq_test_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:otbn_ecdsa_op_irq_test_sim_qemu_sival_rom_ext pass: //sw/device/tests:otbn_irq_test_sim_qemu_rom_with_fake_keys @@ -497,6 +499,7 @@ pass: //sw/device/tests:otbn_rsa_test_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:otbn_rsa_test_sim_qemu_sival_rom_ext pass: //sw/device/tests:otbn_smoketest_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:otbn_smoketest_sim_qemu_sival_rom_ext +pass: //sw/device/tests:otp_ctrl_descrambling_test_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:plic_sw_irq_test_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:plic_sw_irq_test_sim_qemu_sival_rom_ext pass: //sw/device/tests:pmp_smoketest_napot_sim_qemu_rom_with_fake_keys @@ -541,6 +544,8 @@ pass: //sw/device/tests:uart_smoketest_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:uart_smoketest_sim_qemu_sival_rom_ext pass: //sw/device/tests:usbdev_mem_test_sim_qemu_rom_with_fake_keys pass: //sw/device/tests:usbdev_mem_test_sim_qemu_sival_rom_ext +pass: //sw/device/tests:usbdev_vbus_test_sim_qemu_rom_with_fake_keys +pass: //sw/device/tests:usbdev_vbus_test_sim_qemu_sival_rom_ext pass: //third_party/coremark/top_earlgrey:coremark_test_sim_qemu_rom_with_fake_keys pass: //third_party/coremark/top_earlgrey:coremark_test_sim_qemu_sival_rom_ext pass: //third_party/riscv-compliance:C-ADDI16SP_sim_qemu_rom_with_fake_keys