[dif/otp_ctrl] add DIF to check if a partition digest is computed This adds a DIF to check if the partition's digest has been computed, and therefore, determine if a partition has been write-locked. This fixes #12588. Signed-off-by: Timothy Trippel <ttrippel@google.com>
diff --git a/sw/device/lib/dif/dif_otp_ctrl.c b/sw/device/lib/dif/dif_otp_ctrl.c index 7497fca..7ef720b 100644 --- a/sw/device/lib/dif/dif_otp_ctrl.c +++ b/sw/device/lib/dif/dif_otp_ctrl.c
@@ -612,6 +612,65 @@ return kDifOk; } +static bool get_digest_regs(dif_otp_ctrl_partition_t partition, ptrdiff_t *reg0, + ptrdiff_t *reg1) { + switch (partition) { + case kDifOtpCtrlPartitionVendorTest: + *reg0 = OTP_CTRL_VENDOR_TEST_DIGEST_0_REG_OFFSET; + *reg1 = OTP_CTRL_VENDOR_TEST_DIGEST_1_REG_OFFSET; + break; + case kDifOtpCtrlPartitionCreatorSwCfg: + *reg0 = OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_REG_OFFSET; + *reg1 = OTP_CTRL_CREATOR_SW_CFG_DIGEST_1_REG_OFFSET; + break; + case kDifOtpCtrlPartitionOwnerSwCfg: + *reg0 = OTP_CTRL_OWNER_SW_CFG_DIGEST_0_REG_OFFSET; + *reg1 = OTP_CTRL_OWNER_SW_CFG_DIGEST_1_REG_OFFSET; + break; + case kDifOtpCtrlPartitionHwCfg: + *reg0 = OTP_CTRL_HW_CFG_DIGEST_0_REG_OFFSET; + *reg1 = OTP_CTRL_HW_CFG_DIGEST_1_REG_OFFSET; + break; + case kDifOtpCtrlPartitionSecret0: + *reg0 = OTP_CTRL_SECRET0_DIGEST_0_REG_OFFSET; + *reg1 = OTP_CTRL_SECRET0_DIGEST_1_REG_OFFSET; + break; + case kDifOtpCtrlPartitionSecret1: + *reg0 = OTP_CTRL_SECRET1_DIGEST_0_REG_OFFSET; + *reg1 = OTP_CTRL_SECRET1_DIGEST_1_REG_OFFSET; + break; + case kDifOtpCtrlPartitionSecret2: + *reg0 = OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET; + *reg1 = OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET; + break; + default: + return false; + } + + return true; +} + +dif_result_t dif_otp_ctrl_is_digest_computed(const dif_otp_ctrl_t *otp, + dif_otp_ctrl_partition_t partition, + bool *is_computed) { + if (otp == NULL || is_computed == NULL) { + return kDifBadArg; + } + + ptrdiff_t reg0, reg1; + if (!get_digest_regs(partition, ®0, ®1)) { + return kDifBadArg; + } + + uint64_t value = mmio_region_read32(otp->base_addr, reg1); + value <<= 32; + value |= mmio_region_read32(otp->base_addr, reg0); + + *is_computed = value != 0; + + return kDifOk; +} + dif_result_t dif_otp_ctrl_get_digest(const dif_otp_ctrl_t *otp, dif_otp_ctrl_partition_t partition, uint64_t *digest) { @@ -619,43 +678,9 @@ return kDifBadArg; } - // The LC partition does not have a digest. - if (partition == kDifOtpCtrlPartitionLifeCycle) { - return kDifBadArg; - } - ptrdiff_t reg0, reg1; - switch (partition) { - case kDifOtpCtrlPartitionVendorTest: - reg0 = OTP_CTRL_VENDOR_TEST_DIGEST_0_REG_OFFSET; - reg1 = OTP_CTRL_VENDOR_TEST_DIGEST_1_REG_OFFSET; - break; - case kDifOtpCtrlPartitionCreatorSwCfg: - reg0 = OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_REG_OFFSET; - reg1 = OTP_CTRL_CREATOR_SW_CFG_DIGEST_1_REG_OFFSET; - break; - case kDifOtpCtrlPartitionOwnerSwCfg: - reg0 = OTP_CTRL_OWNER_SW_CFG_DIGEST_0_REG_OFFSET; - reg1 = OTP_CTRL_OWNER_SW_CFG_DIGEST_1_REG_OFFSET; - break; - case kDifOtpCtrlPartitionHwCfg: - reg0 = OTP_CTRL_HW_CFG_DIGEST_0_REG_OFFSET; - reg1 = OTP_CTRL_HW_CFG_DIGEST_1_REG_OFFSET; - break; - case kDifOtpCtrlPartitionSecret0: - reg0 = OTP_CTRL_SECRET0_DIGEST_0_REG_OFFSET; - reg1 = OTP_CTRL_SECRET0_DIGEST_1_REG_OFFSET; - break; - case kDifOtpCtrlPartitionSecret1: - reg0 = OTP_CTRL_SECRET1_DIGEST_0_REG_OFFSET; - reg1 = OTP_CTRL_SECRET1_DIGEST_1_REG_OFFSET; - break; - case kDifOtpCtrlPartitionSecret2: - reg0 = OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET; - reg1 = OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET; - break; - default: - return kDifBadArg; + if (!get_digest_regs(partition, ®0, ®1)) { + return kDifBadArg; } uint64_t value = mmio_region_read32(otp->base_addr, reg1);
diff --git a/sw/device/lib/dif/dif_otp_ctrl.h b/sw/device/lib/dif/dif_otp_ctrl.h index 2676913..4558b24 100644 --- a/sw/device/lib/dif/dif_otp_ctrl.h +++ b/sw/device/lib/dif/dif_otp_ctrl.h
@@ -521,6 +521,24 @@ uint64_t digest); /** + * Checks if the digest value for the given partition has been computed. Once a + * digest has been computed for a partition, the partition is write-locked + * (additionally, read-locked if the partition is secret). + * + * The lifecycle partition does not have a digest, and checking if this region + * has a computed digest will return an error. + * + * @param otp An OTP handle. + * @param partition The partition to check the digest of. + * @param[out] is_computed Indicates if the digest has been computed. + * @return The result of the operation. + */ +OT_WARN_UNUSED_RESULT +dif_result_t dif_otp_ctrl_is_digest_computed(const dif_otp_ctrl_t *otp, + dif_otp_ctrl_partition_t partition, + bool *is_computed); + +/** * Gets the buffered digest value for the given partition. * * Note that this value is only updated when the device is reset; if the digest
diff --git a/sw/device/lib/dif/dif_otp_ctrl_unittest.cc b/sw/device/lib/dif/dif_otp_ctrl_unittest.cc index d87884c..f8a4821 100644 --- a/sw/device/lib/dif/dif_otp_ctrl_unittest.cc +++ b/sw/device/lib/dif/dif_otp_ctrl_unittest.cc
@@ -496,6 +496,40 @@ /*digest=*/0xabcdef0000abcdef)); } +class IsDigestComputed : public OtpTest {}; + +TEST_F(IsDigestComputed, NullArgs) { + bool is_computed; + EXPECT_DIF_BADARG(dif_otp_ctrl_is_digest_computed( + nullptr, kDifOtpCtrlPartitionSecret2, &is_computed)); + EXPECT_DIF_BADARG(dif_otp_ctrl_is_digest_computed( + &otp_, kDifOtpCtrlPartitionSecret2, nullptr)); + EXPECT_DIF_BADARG(dif_otp_ctrl_is_digest_computed( + nullptr, kDifOtpCtrlPartitionSecret2, nullptr)); +} + +TEST_F(IsDigestComputed, BadPartition) { + bool is_computed; + EXPECT_DIF_BADARG(dif_otp_ctrl_is_digest_computed( + &otp_, kDifOtpCtrlPartitionLifeCycle, &is_computed)); +} + +TEST_F(IsDigestComputed, Success) { + bool is_computed; + + EXPECT_READ32(OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET, 0x98abcdef); + EXPECT_READ32(OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET, 0xabcdef01); + EXPECT_DIF_OK(dif_otp_ctrl_is_digest_computed( + &otp_, kDifOtpCtrlPartitionSecret2, &is_computed)); + EXPECT_TRUE(is_computed); + + EXPECT_READ32(OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET, 0); + EXPECT_READ32(OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET, 0); + EXPECT_DIF_OK(dif_otp_ctrl_is_digest_computed( + &otp_, kDifOtpCtrlPartitionSecret2, &is_computed)); + EXPECT_FALSE(is_computed); +} + struct DigestParams { dif_otp_ctrl_partition_t partition; ptrdiff_t reg0, reg1;