[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;