All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
To: jorge.ramirez@oss.qualcomm.com, trini@konsulko.com,
	jens.wiklander@linaro.org, ilias.apalodimas@linaro.org,
	neil.armstrong@linaro.org, bhupesh.linux@gmail.com,
	n-francis@ti.com, marek.vasut+renesas@mailbox.org,
	igor.belwon@mentallysanemainliners.org, shawn.lin@rock-chips.com,
	yoshihiro.shimoda.uh@renesas.com, alchark@gmail.com,
	tuyen.dang.xa@renesas.com, macpaul.lin@mediatek.com,
	padmarao.begari@amd.com, jstephan@baylibre.com, bb@ti.com,
	j-mcarthur@ti.com, venkyada@qti.qualcomm.com,
	hayashi.kunihiko@socionext.com
Cc: u-boot@lists.denx.de, sumit.garg@kernel.org
Subject: [PATCH v1 3/7] ufs: rpmb: derive the per-region RPMB CID and size for OP-TEE
Date: Mon, 20 Jul 2026 10:51:43 +0200	[thread overview]
Message-ID: <20260720085202.537019-4-jorge.ramirez@oss.qualcomm.com> (raw)
In-Reply-To: <20260720085202.537019-1-jorge.ramirez@oss.qualcomm.com>

Read the UFS device, unit and geometry descriptors to report each RPMB
region's size and reliable-write count, and build a 16-byte CID by
BLAKE2b-hashing the same device-id string the Linux kernel derives
(ufshcd_create_device_id() plus a "-R<region>" suffix), so OP-TEE derives
an RPMB key that matches Linux. Exposed via ufs_rpmb_get_region_info().

Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
---
 drivers/ufs/ufs-rpmb.c   | 135 ++++++++++++++++++++++++++++++++++++++-
 drivers/ufs/ufs-uclass.c |   4 +-
 drivers/ufs/ufs.h        |  11 ++++
 include/ufs.h            |   6 +-
 4 files changed, 151 insertions(+), 5 deletions(-)

diff --git a/drivers/ufs/ufs-rpmb.c b/drivers/ufs/ufs-rpmb.c
index 636ccb6e74f..7919162ddae 100644
--- a/drivers/ufs/ufs-rpmb.c
+++ b/drivers/ufs/ufs-rpmb.c
@@ -1,8 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0+
 #include <dm.h>
+#include <hexdump.h>
 #include <log.h>
 #include <scsi.h>
 #include <ufs.h>
+#include <vsprintf.h>
+#include <u-boot/blake2.h>
+#include <asm/unaligned.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include "ufs.h"
@@ -130,9 +134,8 @@ struct udevice *ufs_rpmb_get_scsi_dev(int dev_id)
 	return scsi_dev;
 }
 
-int ufs_rpmb_read_geometry(struct udevice *scsi_dev, u8 *rpmb_rw_size)
+static int ufs_rpmb_read_rw_size(struct ufs_hba *hba, u8 *rpmb_rw_size)
 {
-	struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
 	u8 desc[QUERY_DESC_GEOMETRY_DEF_SIZE];
 	int ret;
 
@@ -144,3 +147,131 @@ int ufs_rpmb_read_geometry(struct udevice *scsi_dev, u8 *rpmb_rw_size)
 	*rpmb_rw_size = desc[GEOMETRY_DESC_RPMB_RW_SIZE];
 	return 0;
 }
+
+static int ufs_rpmb_read_region_sizes(struct ufs_hba *hba, u16 spec_ver,
+				      u8 sizes[UFS_RPMB_NUM_REGIONS])
+{
+	u8 unit[QUERY_DESC_UNIT_DEF_SIZE] = { };
+	int ret;
+
+	ret = ufshcd_read_descriptor(hba, QUERY_DESC_IDN_UNIT,
+				     UFS_UPIU_RPMB_WLUN, unit, sizeof(unit));
+	if (ret)
+		return ret;
+
+	memset(sizes, 0, UFS_RPMB_NUM_REGIONS);
+
+	if (spec_ver > UFS_RPMB_LEGACY_SPEC_VER) {
+		sizes[0] = unit[RPMB_UNIT_DESC_REGION0_SIZE];
+		sizes[1] = unit[RPMB_UNIT_DESC_REGION1_SIZE];
+		sizes[2] = unit[RPMB_UNIT_DESC_REGION2_SIZE];
+		sizes[3] = unit[RPMB_UNIT_DESC_REGION3_SIZE];
+	} else {
+		u64 region = (get_unaligned_be64(unit +
+					RPMB_UNIT_DESC_LOGICAL_BLK_COUNT)
+			      << unit[RPMB_UNIT_DESC_LOGICAL_BLK_SIZE])
+			     >> UFS_RPMB_REGION_UNIT_SHIFT;
+
+		sizes[0] = region > 0xff ? 0xff : region;
+	}
+
+	return 0;
+}
+
+static void ufs_rpmb_string_to_ascii(const u8 *raw, char *out, size_t outsz)
+{
+	int nchars = ((int)raw[QUERY_DESC_LENGTH_OFFSET] - QUERY_DESC_HDR_SIZE);
+	int i, n = 0;
+
+	nchars = nchars > 0 ? nchars / 2 : 0;
+	for (i = 0; i < nchars && n < (int)outsz - 1; i++) {
+		u16 c = get_unaligned_be16(raw + QUERY_DESC_HDR_SIZE + i * 2);
+
+		out[n++] = (c >= 0x20 && c <= 0x7e) ? (char)c : ' ';
+	}
+	out[n] = '\0';
+}
+
+static int ufs_rpmb_build_cid(struct ufs_hba *hba, const u8 *dev_desc,
+			      unsigned int region, u8 *cid)
+{
+	u8 raw[QUERY_DESC_MAX_SIZE];
+	char model[MAX_MODEL_LEN * 8];
+	char serial_hex[QUERY_DESC_MAX_SIZE * 2 + 1];
+	char idstr[QUERY_DESC_MAX_SIZE * 3];
+	u8 serial[QUERY_DESC_MAX_SIZE] = { };
+	u16 manf_id, spec_ver, dev_ver, manf_date;
+	u8 blen;
+	int ret;
+
+	manf_id = get_unaligned_be16(dev_desc + DEVICE_DESC_PARAM_MANF_ID);
+	spec_ver = get_unaligned_be16(dev_desc + DEVICE_DESC_PARAM_SPEC_VER);
+	dev_ver = get_unaligned_be16(dev_desc + DEVICE_DESC_PARAM_DEV_VER);
+	manf_date = get_unaligned_be16(dev_desc + DEVICE_DESC_PARAM_MANF_DATE);
+
+	ret = ufshcd_read_descriptor(hba, QUERY_DESC_IDN_STRING,
+				     dev_desc[DEVICE_DESC_PARAM_PRDCT_NAME],
+				     raw, sizeof(raw));
+	if (ret)
+		return ret;
+	ufs_rpmb_string_to_ascii(raw, model, sizeof(model));
+
+	ret = ufshcd_read_descriptor(hba, QUERY_DESC_IDN_STRING,
+				     dev_desc[DEVICE_DESC_PARAM_SN],
+				     raw, sizeof(raw));
+	if (ret)
+		return ret;
+	blen = raw[QUERY_DESC_LENGTH_OFFSET];
+	if (blen < QUERY_DESC_HDR_SIZE)
+		return -EINVAL;
+	memcpy(serial, raw + QUERY_DESC_HDR_SIZE, blen - QUERY_DESC_HDR_SIZE);
+	bin2hex(serial_hex, serial, blen);
+	serial_hex[blen * 2] = '\0';
+
+	snprintf(idstr, sizeof(idstr), "%04X-%04X-%s-%s-%04X-%04X-R%u",
+		 manf_id, spec_ver, model, serial_hex, dev_ver, manf_date,
+		 region);
+
+	if (blake2b(cid, UFS_RPMB_CID_SIZE, idstr, strlen(idstr), NULL, 0))
+		return -EIO;
+
+	return 0;
+}
+
+int ufs_rpmb_get_region_info(struct udevice *scsi_dev, unsigned int region,
+			     u8 *size_mult, u8 *rel_wr, u8 *cid)
+{
+	struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
+	u8 dev_desc[QUERY_DESC_DEVICE_DEF_SIZE] = { };
+	u8 sizes[UFS_RPMB_NUM_REGIONS];
+	u16 spec_ver;
+	int ret;
+
+	if (region >= UFS_RPMB_NUM_REGIONS)
+		return 0;
+
+	ret = ufshcd_read_descriptor(hba, QUERY_DESC_IDN_DEVICE, 0,
+				     dev_desc, sizeof(dev_desc));
+	if (ret)
+		return ret;
+	spec_ver = get_unaligned_be16(dev_desc + DEVICE_DESC_PARAM_SPEC_VER);
+
+	ret = ufs_rpmb_read_region_sizes(hba, spec_ver, sizes);
+	if (ret)
+		return ret;
+	if (!sizes[region])
+		return 0;
+
+	ret = ufs_rpmb_read_rw_size(hba, rel_wr);
+	if (ret)
+		return ret;
+	if (!*rel_wr)
+		*rel_wr = 1;
+
+	ret = ufs_rpmb_build_cid(hba, dev_desc, region, cid);
+	if (ret)
+		return ret;
+
+	*size_mult = sizes[region];
+	return 1;
+}
diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
index 962b6093762..f5e5bfd2e27 100644
--- a/drivers/ufs/ufs-uclass.c
+++ b/drivers/ufs/ufs-uclass.c
@@ -1800,8 +1800,8 @@ out:
 	return err;
 }
 
-static int ufs_get_device_desc(struct ufs_hba *hba,
-			       struct ufs_dev_desc *dev_desc)
+int ufs_get_device_desc(struct ufs_hba *hba,
+			struct ufs_dev_desc *dev_desc)
 {
 	int err;
 	size_t buff_len;
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
index e66d2c5f533..cf89bbc2008 100644
--- a/drivers/ufs/ufs.h
+++ b/drivers/ufs/ufs.h
@@ -20,6 +20,15 @@ struct udevice;
 #define UFS_RPMB_SEC_PROTOCOL_ID	0x01
 
 #define GEOMETRY_DESC_RPMB_RW_SIZE	0x17
+
+#define RPMB_UNIT_DESC_LOGICAL_BLK_SIZE		0x0A
+#define RPMB_UNIT_DESC_LOGICAL_BLK_COUNT	0x0B
+#define RPMB_UNIT_DESC_REGION0_SIZE		0x13
+#define RPMB_UNIT_DESC_REGION1_SIZE		0x14
+#define RPMB_UNIT_DESC_REGION2_SIZE		0x15
+#define RPMB_UNIT_DESC_REGION3_SIZE		0x16
+#define UFS_RPMB_LEGACY_SPEC_VER		0x0220
+#define UFS_RPMB_REGION_UNIT_SHIFT		17
 #define UPIU_TRANSACTION_UIC_CMD 0x1F
 #define UIC_CMD_SIZE (sizeof(u32) * 4)
 #define RESPONSE_UPIU_SENSE_DATA_LENGTH	18
@@ -822,4 +831,6 @@ int ufshcd_probe(struct udevice *dev, struct ufs_hba_ops *hba_ops);
 int ufshcd_read_descriptor(struct ufs_hba *hba, enum desc_idn desc_id,
 			   int desc_index, u8 *buf, u8 size);
 
+int ufs_get_device_desc(struct ufs_hba *hba, struct ufs_dev_desc *dev_desc);
+
 #endif
diff --git a/include/ufs.h b/include/ufs.h
index 90c6aebcec1..79573e02278 100644
--- a/include/ufs.h
+++ b/include/ufs.h
@@ -20,12 +20,16 @@ int ufs_probe(void);
  */
 int ufs_probe_dev(int index);
 
+#define UFS_RPMB_CID_SIZE	16
+#define UFS_RPMB_NUM_REGIONS	4
+
 struct udevice *ufs_rpmb_get_scsi_dev(int dev_id);
 
 int ufs_rpmb_route_frames(struct udevice *scsi_dev, unsigned int region,
 			  void *req, unsigned long reqlen, void *rsp,
 			  unsigned long rsplen);
 
-int ufs_rpmb_read_geometry(struct udevice *scsi_dev, u8 *rpmb_rw_size);
+int ufs_rpmb_get_region_info(struct udevice *scsi_dev, unsigned int region,
+			     u8 *size_mult, u8 *rel_wr, u8 *cid);
 
 #endif
-- 
2.54.0


  parent reply	other threads:[~2026-07-20  8:52 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-20  8:51 [PATCH v1 0/7] ufs: rpmb: route OP-TEE RPMB secure storage over UFS Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 1/7] ufs: decode string descriptors as UTF-16 big-endian Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 2/7] ufs: add RPMB transport over SCSI SECURITY PROTOCOL Jorge Ramirez-Ortiz
2026-07-20  8:51 ` Jorge Ramirez-Ortiz [this message]
2026-07-20  8:51 ` [PATCH v1 4/7] ufs: rpmb: retry SECURITY PROTOCOL on power-on UNIT ATTENTION Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 5/7] ufs: rpmb: bounce unaligned frames through a DMA-aligned buffer Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 6/7] optee: rename rpmb.c to rpmb_legacy.c Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 7/7] optee: implement the RPMB subsystem interface for UFS Jorge Ramirez-Ortiz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260720085202.537019-4-jorge.ramirez@oss.qualcomm.com \
    --to=jorge.ramirez@oss.qualcomm.com \
    --cc=alchark@gmail.com \
    --cc=bb@ti.com \
    --cc=bhupesh.linux@gmail.com \
    --cc=hayashi.kunihiko@socionext.com \
    --cc=igor.belwon@mentallysanemainliners.org \
    --cc=ilias.apalodimas@linaro.org \
    --cc=j-mcarthur@ti.com \
    --cc=jens.wiklander@linaro.org \
    --cc=jstephan@baylibre.com \
    --cc=macpaul.lin@mediatek.com \
    --cc=marek.vasut+renesas@mailbox.org \
    --cc=n-francis@ti.com \
    --cc=neil.armstrong@linaro.org \
    --cc=padmarao.begari@amd.com \
    --cc=shawn.lin@rock-chips.com \
    --cc=sumit.garg@kernel.org \
    --cc=trini@konsulko.com \
    --cc=tuyen.dang.xa@renesas.com \
    --cc=u-boot@lists.denx.de \
    --cc=venkyada@qti.qualcomm.com \
    --cc=yoshihiro.shimoda.uh@renesas.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.