mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/9] Add RPMB support
@ 2025-03-12 12:16 Sascha Hauer
  2025-03-12 12:16 ` [PATCH 1/9] mci: implement mci_set_blockcount() Sascha Hauer
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

This series adds the necessary pieces to provide OP-TEE access to RPMB
partitions under barebox.

With this OP-TEE can issue RPMB requests to barebox and barebox will
answer them accordingly.

OP-TEE will only access the RPMB when triggered by barebox. For this
purpose I implemented access to the Android Verified Boot (AVB) variable
store. This is implemented in U-Boot as well and the code is loosely
based on it. The variables can be read/written using the newly
introduced avb_pvalue command.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Sascha Hauer (9):
      mci: implement mci_set_blockcount()
      mci: export some functions for RPMB support
      mci: detect RPMB partitions
      mci: add RPMB support
      tee: optee: probe successfully even when no devices are found
      tee: optee: implement shared mem alloc/free RPC commands
      tee: optee: implement RPMB support
      tee: optee: implement AVB named persistent values support
      commands: add avb_pvalue command

 commands/Kconfig                  |  13 +++
 commands/Makefile                 |   1 +
 commands/avb_pvalue.c             | 138 +++++++++++++++++++++++++
 drivers/mci/Kconfig               |   3 +
 drivers/mci/Makefile              |   1 +
 drivers/mci/mci-core.c            |  73 +++++++++++++-
 drivers/mci/rpmb.c                | 206 ++++++++++++++++++++++++++++++++++++++
 drivers/tee/optee/Kconfig         |   9 ++
 drivers/tee/optee/Makefile        |   2 +
 drivers/tee/optee/avb.c           | 189 ++++++++++++++++++++++++++++++++++
 drivers/tee/optee/device.c        |   1 +
 drivers/tee/optee/optee_private.h |  13 +++
 drivers/tee/optee/optee_rpc_cmd.h | 144 ++++++++++++++++++++++++++
 drivers/tee/optee/rpc.c           |  63 +++++++++++-
 drivers/tee/optee/rpmb.c          | 128 +++++++++++++++++++++++
 drivers/tee/optee/smc_abi.c       |  26 +++--
 drivers/tee/tee_shm.c             |   1 +
 include/linux/tee_drv.h           |   1 +
 include/mci.h                     |  17 +++-
 include/tee/avb.h                 |   9 ++
 20 files changed, 1021 insertions(+), 17 deletions(-)
---
base-commit: a9a50228674d01adc8d7a49d1ab0e7e894c25fe8
change-id: 20250312-rpmb-c6f330f29cb1

Best regards,
-- 
Sascha Hauer <s.hauer@pengutronix.de>




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/9] mci: implement mci_set_blockcount()
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  2025-03-12 12:16 ` [PATCH 2/9] mci: export some functions for RPMB support Sascha Hauer
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

This adds a function to send a MMC_CMD_SET_BLOCK_COUNT command. This
is not yet needed by barebox as we use open end multiblock transfers,
but will be needed by upcoming RPMB support.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/mci-core.c | 9 +++++++++
 include/mci.h          | 5 +++++
 2 files changed, 14 insertions(+)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 27a10df9ce..6d8140f7b0 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -311,6 +311,15 @@ static int mci_block_erase(struct mci *card, unsigned int from,
 	return -EIO;
 }
 
+int mci_set_blockcount(struct mci *mci, unsigned int cmdarg)
+{
+	struct mci_cmd cmd = {};
+
+	mci_setup_cmd(&cmd, MMC_CMD_SET_BLOCK_COUNT, cmdarg, MMC_RSP_R1);
+
+	return mci_send_cmd(mci, &cmd, NULL);
+}
+
 static int mci_do_block_op(struct mci *mci, const void *src, void *dst, int blocknum,
 		int blocks)
 {
diff --git a/include/mci.h b/include/mci.h
index f0db1f9ea0..c6ee6ea50f 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -87,12 +87,16 @@
 #define MMC_CMD_READ_MULTIPLE_BLOCK	18
 #define MMC_SEND_TUNING_BLOCK		19   /* adtc R1  */
 #define MMC_SEND_TUNING_BLOCK_HS200	21   /* adtc R1  */
+#define MMC_CMD_SET_BLOCK_COUNT		23
 #define MMC_CMD_WRITE_SINGLE_BLOCK	24
 #define MMC_CMD_WRITE_MULTIPLE_BLOCK	25
 #define MMC_CMD_APP_CMD			55
 #define MMC_CMD_SPI_READ_OCR		58
 #define MMC_CMD_SPI_CRC_ON_OFF		59
 
+#define MMC_CMD23_ARG_BLOCKS	GENMASK(15, 0)
+#define MMC_CMD23_ARG_REL_WR	BIT(31)
+
   /* class 5 */
 #define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
 #define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
@@ -724,6 +728,7 @@ int mmc_hs200_tuning(struct mci *mci);
 int mci_execute_tuning(struct mci *mci);
 int mci_send_abort_tuning(struct mci *mci, u32 opcode);
 int mmc_select_timing(struct mci *mci);
+int mci_set_blockcount(struct mci *mci, unsigned int cmdarg);
 
 static inline bool mmc_card_hs200(struct mci *mci)
 {

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/9] mci: export some functions for RPMB support
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
  2025-03-12 12:16 ` [PATCH 1/9] mci: implement mci_set_blockcount() Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  2025-03-12 12:16 ` [PATCH 3/9] mci: detect RPMB partitions Sascha Hauer
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

Export mci_send_cmd() and mci_blk_part_switch() in preparation for
adding RPMB support.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/mci-core.c | 4 ++--
 include/mci.h          | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 6d8140f7b0..b7ea0df3cb 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -68,7 +68,7 @@ static inline unsigned mci_caps(struct mci *mci)
  * @param data The data according to the command (can be NULL)
  * @return Driver's answer (0 on success)
  */
-static int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd, struct mci_data *data)
+int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd, struct mci_data *data)
 {
 	struct mci_host *host = mci->host;
 
@@ -2030,7 +2030,7 @@ static int sd_send_if_cond(struct mci *mci)
 /**
  * Switch between hardware MMC partitions on demand
  */
-static int mci_blk_part_switch(struct mci_part *part)
+int mci_blk_part_switch(struct mci_part *part)
 {
 	struct mci *mci = part->mci;
 	int ret;
diff --git a/include/mci.h b/include/mci.h
index c6ee6ea50f..8084df813a 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -729,6 +729,8 @@ int mci_execute_tuning(struct mci *mci);
 int mci_send_abort_tuning(struct mci *mci, u32 opcode);
 int mmc_select_timing(struct mci *mci);
 int mci_set_blockcount(struct mci *mci, unsigned int cmdarg);
+int mci_blk_part_switch(struct mci_part *part);
+int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd, struct mci_data *data);
 
 static inline bool mmc_card_hs200(struct mci *mci)
 {

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/9] mci: detect RPMB partitions
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
  2025-03-12 12:16 ` [PATCH 1/9] mci: implement mci_set_blockcount() Sascha Hauer
  2025-03-12 12:16 ` [PATCH 2/9] mci: export some functions for RPMB support Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  2025-03-12 12:16 ` [PATCH 4/9] mci: add RPMB support Sascha Hauer
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

Detect RPMB partitions and initialize a struct mci_part for them. We do
not actually register the RPMB partitions as we can't access them with
regular mci_do_block_op() and we would only access encrypted data anyway.

Right now we assume that only one RPMB is present in a system which
covers the 99% case. Should there be multiple RPMBs found we issue a
warning message as there is no way to specify which one shall be used,
the first one found will be used which may vary depending on probe
order.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/mci-core.c | 36 ++++++++++++++++++++++++++++++++++++
 include/mci.h          |  7 ++++++-
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index b7ea0df3cb..18c910c4c3 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -647,6 +647,15 @@ static blkcnt_t mci_calc_blk_cnt(blkcnt_t cap, unsigned shift)
 	return ret;
 }
 
+/*
+ * We currently only support a single RPMB partition. Most systems only have a
+ * single eMMC and thus only one RPMB partition, so we are fine on most systems.
+ * When multiple RPMB partitions are found we issue a warning message as the
+ * first RPMB found will be used. There currently is no way to specify which one
+ * shall be used.
+ */
+static struct mci_part *rpmb_partition;
+
 static void mci_part_add(struct mci *mci, uint64_t size,
                         unsigned int part_cfg, char *name, char *partname, int idx, bool ro,
                         int area_type)
@@ -671,6 +680,16 @@ static void mci_part_add(struct mci *mci, uint64_t size,
 	part->part_cfg = part_cfg;
 	part->idx = idx;
 
+	if (area_type == MMC_BLK_DATA_AREA_RPMB) {
+		mci->rpmb_part = part;
+		if (rpmb_partition) {
+			dev_warn(&mci->dev, "Multiple RPMB partitions found. Only %s will be used\n",
+				 rpmb_partition->mci->host->devname);
+		} else {
+			rpmb_partition = mci->rpmb_part;
+		}
+	}
+
 	if (area_type == MMC_BLK_DATA_AREA_MAIN) {
 		cdev_set_of_node(&part->blk.cdev, mci->host->hw_dev->of_node);
 		part->blk.cdev.flags |= DEVFS_IS_MCI_MAIN_PART_DEV;
@@ -822,6 +841,20 @@ static int mmc_change_freq(struct mci *mci)
 		mci->boot_ack_enable = (mci->ext_csd_part_config >> 6) & 0x1;
 	}
 
+	if (mci->ext_csd[EXT_CSD_REV] >= 5) {
+		if (mci->ext_csd[EXT_CSD_RPMB_SIZE_MULT]) {
+			char *name, *partname;
+
+			partname = basprintf("rpmb");
+			name = basprintf("%s.%s", mci->cdevname, partname);
+
+			mci_part_add(mci, mci->ext_csd[EXT_CSD_RPMB_SIZE_MULT] << 17,
+				EXT_CSD_PART_CONFIG_ACC_RPMB,
+				name, partname, 0, false,
+				MMC_BLK_DATA_AREA_RPMB);
+		}
+	}
+
 	if (IS_ENABLED(CONFIG_MCI_MMC_GPP_PARTITIONS))
 		mmc_extract_gpp_partitions(mci);
 
@@ -2601,6 +2634,9 @@ static int mci_register_partition(struct mci_part *part)
 	part->blk.ops = &mci_ops;
 	part->blk.type = IS_SD(mci) ? BLK_TYPE_SD : BLK_TYPE_MMC;
 
+	if (part->area_type == MMC_BLK_DATA_AREA_RPMB)
+		return 0;
+
 	rc = blockdevice_register(&part->blk);
 	if (rc != 0) {
 		dev_err(&mci->dev, "Failed to register MCI/SD blockdevice\n");
diff --git a/include/mci.h b/include/mci.h
index 8084df813a..08a3e46f7d 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -347,6 +347,7 @@
  */
 #define EXT_CSD_PART_CONFIG_ACC_MASK	(0x7)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT0	(0x1)
+#define EXT_CSD_PART_CONFIG_ACC_RPMB	(0x3)
 #define EXT_CSD_PART_CONFIG_ACC_GPP0	(0x4)
 
 #define EXT_CSD_CMD_SET_NORMAL		(1<<0)
@@ -606,9 +607,11 @@ struct mci_host {
 #define MMC_NUM_BOOT_PARTITION	2
 #define MMC_NUM_GP_PARTITION	4
 #define MMC_NUM_USER_PARTITION	1
+#define MMC_NUM_RPMB_PARTITION	1
 #define MMC_NUM_PHY_PARTITION	(MMC_NUM_BOOT_PARTITION + \
                                  MMC_NUM_GP_PARTITION + \
-                                 MMC_NUM_USER_PARTITION)
+                                 MMC_NUM_USER_PARTITION + \
+                                 MMC_NUM_RPMB_PARTITION)
 
 struct mci_part {
 	struct block_device	blk;		/**< the blockdevice for the card */
@@ -674,6 +677,8 @@ struct mci {
 	int boot_ack_enable;
 
 	struct mci_part part[MMC_NUM_PHY_PARTITION];
+	struct mci_part *rpmb_part;
+
 	int nr_parts;
 	char *cdevname;
 

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 4/9] mci: add RPMB support
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
                   ` (2 preceding siblings ...)
  2025-03-12 12:16 ` [PATCH 3/9] mci: detect RPMB partitions Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  2025-03-12 12:16 ` [PATCH 5/9] tee: optee: probe successfully even when no devices are found Sascha Hauer
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

This implements the MMC specific part to access RPMB partitions:

- Provide a function to find a RPMB capable eMMC
- partition switching to the RPMB partition
- Dissecting the OP-TEE requests into the correspnding MMC read/write
  multiblock commands

For now we only support a single eMMC RPMB partition per board. This is
the 99% case, but there might be systems with multiple eMMCs. The OP-TEE
protocol has a dev_id field to support multiple eMMCs, but OP-TEE itself
currently only supports a single RPMB. This means we really only need to
support one eMMC, but should there be multiple eMMCs on a system we will
need a way for the user to specify which one shall be used. As of now
the first one found will be used.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/Kconfig    |   3 +
 drivers/mci/Makefile   |   1 +
 drivers/mci/mci-core.c |  24 +++++-
 drivers/mci/rpmb.c     | 206 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/mci.h          |   3 +
 5 files changed, 236 insertions(+), 1 deletion(-)

diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 4641e9cdcd..09648aa771 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -68,6 +68,9 @@ config MCI_MMC_GPP_PARTITIONS
 	  Note: by default, 'MMC' devices have no 'general purpose partitions',
 	  it requires a special one-time configuration step to enable them.
 
+config MCI_MMC_RPMB
+	bool "Support eMMC replay protected memory block (RPMB)"
+
 comment "--- MCI host drivers ---"
 
 config MCI_DWC_MSHC
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index 5e951d695f..d3df4c1bb6 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_MCI)		+= mci-core.o
+obj-$(CONFIG_MCI_MMC_RPMB)	+= rpmb.o
 obj-$(CONFIG_MCI_AM654)		+= am654-sdhci.o
 obj-$(CONFIG_MCI_ARASAN)	+= arasan-sdhci.o
 obj-$(CONFIG_MCI_ATMEL)		+= atmel_mci.o atmel_mci_common.o
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 18c910c4c3..9c3b35c23f 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -2068,7 +2068,9 @@ int mci_blk_part_switch(struct mci_part *part)
 	struct mci *mci = part->mci;
 	int ret;
 
-	if (!IS_ENABLED(CONFIG_MCI_MMC_BOOT_PARTITIONS) && !IS_ENABLED(CONFIG_MCI_MMC_GPP_PARTITIONS))
+	if (!IS_ENABLED(CONFIG_MCI_MMC_BOOT_PARTITIONS) &&
+	    !IS_ENABLED(CONFIG_MCI_MMC_GPP_PARTITIONS) &&
+	    !IS_ENABLED(CONFIG_MCI_MMC_RPMB))
 		return 0; /* no need */
 
 	if (mci->part_curr == part)
@@ -3067,3 +3069,23 @@ struct mci *mci_get_device_by_name(const char *name)
 
 	return NULL;
 }
+
+struct mci *mci_get_rpmb_dev(void)
+{
+	struct mci *mci;
+
+	if (rpmb_partition)
+		return rpmb_partition->mci;
+
+	list_for_each_entry(mci, &mci_list, list) {
+		if (mci->host->caps2 & MMC_CAP2_NO_MMC)
+			continue;
+
+		mci_detect_card(mci->host);
+
+		if (rpmb_partition)
+			return rpmb_partition->mci;
+	}
+
+	return NULL;
+}
diff --git a/drivers/mci/rpmb.c b/drivers/mci/rpmb.c
new file mode 100644
index 0000000000..5c98222bad
--- /dev/null
+++ b/drivers/mci/rpmb.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014, Staubli Faverges
+ * Pierre Aubert
+ *
+ * eMMC- Replay Protected Memory Block
+ * According to JEDEC Standard No. 84-A441
+ */
+
+#include <mci.h>
+#include <malloc.h>
+#include <dma.h>
+
+int mmc_rpmb_route_frames(struct mci *mci, void *req, unsigned long reqlen,
+			  void *rsp, unsigned long rsplen);
+
+/**
+ * struct rpmb_frame - rpmb frame as defined by eMMC 5.1 (JESD84-B51)
+ *
+ * @stuff        : stuff bytes
+ * @key_mac      : The authentication key or the message authentication
+ *                 code (MAC) depending on the request/response type.
+ *                 The MAC will be delivered in the last (or the only)
+ *                 block of data.
+ * @data         : Data to be written or read by signed access.
+ * @nonce        : Random number generated by the host for the requests
+ *                 and copied to the response by the RPMB engine.
+ * @write_counter: Counter value for the total amount of the successful
+ *                 authenticated data write requests made by the host.
+ * @addr         : Address of the data to be programmed to or read
+ *                 from the RPMB. Address is the serial number of
+ *                 the accessed block (half sector 256B).
+ * @block_count  : Number of blocks (half sectors, 256B) requested to be
+ *                 read/programmed.
+ * @result       : Includes information about the status of the write counter
+ *                 (valid, expired) and result of the access made to the RPMB.
+ * @req_resp     : Defines the type of request and response to/from the memory.
+ *
+ * The stuff bytes and big-endian properties are modeled to fit to the spec.
+ */
+struct rpmb_frame {
+	u8 stuff[196];
+	u8 key_mac[32];
+	u8 data[256];
+	u8 nonce[16];
+	__be32 write_counter;
+	__be16 addr;
+	__be16 block_count;
+	__be16 result;
+	__be16 req_resp;
+} __packed;
+
+#define RPMB_PROGRAM_KEY	0x1	/* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER	0x2	/* Read RPMB write counter */
+#define RPMB_WRITE_DATA		0x3	/* Write data to RPMB partition */
+#define RPMB_READ_DATA		0x4	/* Read data from RPMB partition */
+#define RPMB_RESULT_READ	0x5	/* Read result request  (Internal) */
+
+static int mci_read_write_blocks(struct mci *mci, u32 opcode, int write_flag, void *buf,
+				 unsigned int buf_bytes)
+{
+	int blocks = buf_bytes / 512;
+	struct mci_cmd cmd = {
+		.cmdidx = opcode,
+		.resp_type = MMC_RSP_R1,
+	};
+	struct mci_data data = {
+		.blocks = blocks,
+		.blocksize = sizeof(struct rpmb_frame),
+	};
+	int ret;
+
+	if (write_flag) {
+		data.src = buf;
+		data.flags = MMC_DATA_WRITE;
+	} else {
+		data.dest = buf;
+		data.flags = MMC_DATA_READ;
+	}
+
+	ret = mci_set_blockcount(mci, blocks | (write_flag & MMC_CMD23_ARG_REL_WR));
+	if (ret)
+		return ret;
+
+	return mci_send_cmd(mci, &cmd, &data);
+}
+
+static int rpmb_route_frames(struct mci *mci, void *req,
+			     unsigned int req_len, void *resp,
+			     unsigned int resp_len)
+{
+	struct rpmb_frame *frm = req;
+	unsigned int cmd_count;
+	u16 req_type;
+	bool write;
+	int ret;
+
+	if (req_len < sizeof(*frm))
+		return -EINVAL;
+
+	req_type = be16_to_cpu(frm->req_resp);
+	switch (req_type) {
+	case RPMB_PROGRAM_KEY:
+		if (req_len != sizeof(struct rpmb_frame) ||
+		    resp_len != sizeof(struct rpmb_frame))
+			return -EINVAL;
+		write = true;
+		break;
+	case RPMB_GET_WRITE_COUNTER:
+		if (req_len != sizeof(struct rpmb_frame) ||
+		    resp_len != sizeof(struct rpmb_frame))
+			return -EINVAL;
+		write = false;
+		break;
+	case RPMB_WRITE_DATA:
+		if (req_len % sizeof(struct rpmb_frame) ||
+		    resp_len != sizeof(struct rpmb_frame))
+			return -EINVAL;
+		write = true;
+		break;
+	case RPMB_READ_DATA:
+		if (req_len != sizeof(struct rpmb_frame) ||
+		    resp_len % sizeof(struct rpmb_frame))
+			return -EINVAL;
+		write = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (write)
+		cmd_count = 3;
+	else
+		cmd_count = 2;
+
+	if (write) {
+		struct rpmb_frame *frm = resp;
+
+		/* Send write request frame(s) */
+		ret = mci_read_write_blocks(mci, MMC_CMD_WRITE_MULTIPLE_BLOCK,
+			  1 | MMC_CMD23_ARG_REL_WR, req, req_len);
+		if (ret)
+			goto out;
+
+		/* Send result request frame */
+		memset(frm, 0, sizeof(*frm));
+		frm->req_resp = cpu_to_be16(RPMB_RESULT_READ);
+		ret = mci_read_write_blocks(mci, MMC_CMD_WRITE_MULTIPLE_BLOCK, 1,
+					    resp, resp_len);
+		if (ret)
+			goto out;
+
+		/* Read response frame */
+		ret = mci_read_write_blocks(mci, MMC_CMD_READ_MULTIPLE_BLOCK, 0,
+					    resp, resp_len);
+		if (ret)
+			goto out;
+	} else {
+		/* Send write request frame(s) */
+		ret = mci_read_write_blocks(mci, MMC_CMD_WRITE_MULTIPLE_BLOCK, 1,
+					    req, req_len);
+		if (ret)
+			goto out;
+
+		/* Read response frame */
+		ret = mci_read_write_blocks(mci, MMC_CMD_READ_MULTIPLE_BLOCK, 0,
+					    resp, resp_len);
+		if (ret)
+			goto out;
+	}
+out:
+	return ret;
+}
+
+int mci_rpmb_route_frames(struct mci *mci, void *req, unsigned long reqlen,
+			  void *rsp, unsigned long rsplen)
+{
+	/*
+	 * Whoever crafted the data supplied to this function knows how to
+	 * format the PRMB frames and which response is expected. If
+	 * there's some unexpected mismatch it's more helpful to report an
+	 * error immediately than trying to guess what was the intention
+	 * and possibly just delay an eventual error which will be harder
+	 * to track down.
+	 */
+	void *rpmb_data = NULL;
+	int ret;
+
+	mci_blk_part_switch(mci->rpmb_part);
+
+	if (!IS_ALIGNED((uintptr_t)req, ARCH_DMA_MINALIGN)) {
+		/* Memory alignment is required by MMC driver */
+		rpmb_data = dma_alloc(reqlen);
+		if (!rpmb_data)
+			return -ENOMEM;
+
+		memcpy(rpmb_data, req, reqlen);
+		req = rpmb_data;
+	}
+
+	ret = rpmb_route_frames(mci, req, reqlen, rsp, rsplen);
+
+	free(rpmb_data);
+
+	return ret;
+}
diff --git a/include/mci.h b/include/mci.h
index 08a3e46f7d..ec0390eedf 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -736,6 +736,9 @@ int mmc_select_timing(struct mci *mci);
 int mci_set_blockcount(struct mci *mci, unsigned int cmdarg);
 int mci_blk_part_switch(struct mci_part *part);
 int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd, struct mci_data *data);
+struct mci *mci_get_rpmb_dev(void);
+int mci_rpmb_route_frames(struct mci *mci, void *req, unsigned long reqlen,
+			  void *rsp, unsigned long rsplen);
 
 static inline bool mmc_card_hs200(struct mci *mci)
 {

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 5/9] tee: optee: probe successfully even when no devices are found
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
                   ` (3 preceding siblings ...)
  2025-03-12 12:16 ` [PATCH 4/9] mci: add RPMB support Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  2025-03-12 12:16 ` [PATCH 6/9] tee: optee: implement shared mem alloc/free RPC commands Sascha Hauer
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

OP-TEE iterates over the devices and when none are found the OP-TEE
driver returns with an error. Return successfully instead because
for example RPMB support doesn't require any devices exported from
OP-TEE.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/tee/optee/device.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c
index 100a877395..5176989a50 100644
--- a/drivers/tee/optee/device.c
+++ b/drivers/tee/optee/device.c
@@ -115,6 +115,7 @@ static int __optee_enumerate_devices(u32 func)
 		goto out_sess;
 	if (!shm_size) {
 		pr_debug("device enumeration PTA found, but no devices!\n");
+		rc = 0;
 		goto out_sess;
 	}
 

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 6/9] tee: optee: implement shared mem alloc/free RPC commands
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
                   ` (4 preceding siblings ...)
  2025-03-12 12:16 ` [PATCH 5/9] tee: optee: probe successfully even when no devices are found Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  2025-03-12 12:16 ` [PATCH 7/9] tee: optee: implement RPMB support Sascha Hauer
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

This implements the OPTEE_RPC_CMD_SHM_ALLOC and OPTEE_RPC_CMD_SHM_FREE
commands to let the secure world allocate and free shared memory.

When OP-TEE calls into the nonsecure world in order to allocate shared
memory we'll need a list of pages returned to the secure world. This
is needed in two cases: once when we call into OP-TEE to register the
shared memory with OP-TEE and once in the return parameters of the
OPTEE_RPC_CMD_SHM_ALLOC RPC call. The U-Boot code this code is based on
allocates two separate page lists. In barebox we attach the page list
to the shared memory object instead so that we have to allocate and
initialize it only once.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/tee/optee/optee_private.h |   3 +
 drivers/tee/optee/optee_rpc_cmd.h | 144 ++++++++++++++++++++++++++++++++++++++
 drivers/tee/optee/rpc.c           |  60 +++++++++++++++-
 drivers/tee/optee/smc_abi.c       |  26 ++++---
 drivers/tee/tee_shm.c             |   1 +
 include/linux/tee_drv.h           |   1 +
 6 files changed, 222 insertions(+), 13 deletions(-)

diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index 637d3195be..d739a6c609 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -17,7 +17,10 @@
 
 /* Some Global Platform error codes used in this driver */
 #define TEEC_SUCCESS			0x00000000
+#define TEEC_ERROR_GENERIC		0xffff0000
 #define TEEC_ERROR_BAD_PARAMETERS	0xFFFF0006
+#define TEEC_ERROR_ITEM_NOT_FOUND	0xffff0008
+#define TEEC_ERROR_NOT_IMPLEMENTED	0xFFFF0009
 #define TEEC_ERROR_NOT_SUPPORTED	0xFFFF000A
 #define TEEC_ERROR_COMMUNICATION	0xFFFF000E
 #define TEEC_ERROR_OUT_OF_MEMORY	0xFFFF000C
diff --git a/drivers/tee/optee/optee_rpc_cmd.h b/drivers/tee/optee/optee_rpc_cmd.h
new file mode 100644
index 0000000000..3ef5672be7
--- /dev/null
+++ b/drivers/tee/optee/optee_rpc_cmd.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2016-2021, Linaro Limited
+ */
+
+#ifndef __OPTEE_RPC_CMD_H
+#define __OPTEE_RPC_CMD_H
+
+/*
+ * All RPC is done with a struct optee_msg_arg as bearer of information,
+ * struct optee_msg_arg::arg holds values defined by OPTEE_RPC_CMD_* below.
+ * Only the commands handled by the kernel driver are defined here.
+ *
+ * RPC communication with tee-supplicant is reversed compared to normal
+ * client communication described above. The supplicant receives requests
+ * and sends responses.
+ */
+
+#define OPTEE_RPC_CMD_RPMB		1
+
+/*
+ * Get time
+ *
+ * Returns number of seconds and nano seconds since the Epoch,
+ * 1970-01-01 00:00:00 +0000 (UTC).
+ *
+ * [out]    value[0].a	    Number of seconds
+ * [out]    value[0].b	    Number of nano seconds.
+ */
+#define OPTEE_RPC_CMD_GET_TIME		3
+
+/*
+ * Notification from/to secure world.
+ *
+ * If secure world needs to wait for something, for instance a mutex, it
+ * does a notification wait request instead of spinning in secure world.
+ * Conversely can a synchronous notification can be sent when a secure
+ * world mutex with a thread waiting thread is unlocked.
+ *
+ * This interface can also be used to wait for a asynchronous notification
+ * which instead is sent via a non-secure interrupt.
+ *
+ * Waiting on notification
+ * [in]    value[0].a	    OPTEE_RPC_NOTIFICATION_WAIT
+ * [in]    value[0].b	    notification value
+ * [in]    value[0].c	    timeout in milliseconds or 0 if no timeout
+ *
+ * Sending a synchronous notification
+ * [in]    value[0].a	    OPTEE_RPC_NOTIFICATION_SEND
+ * [in]    value[0].b	    notification value
+ */
+#define OPTEE_RPC_CMD_NOTIFICATION	4
+#define OPTEE_RPC_NOTIFICATION_WAIT	0
+#define OPTEE_RPC_NOTIFICATION_SEND	1
+
+/*
+ * Suspend execution
+ *
+ * [in]    value[0].a	Number of milliseconds to suspend
+ */
+#define OPTEE_RPC_CMD_SUSPEND		5
+
+/*
+ * Allocate a piece of shared memory
+ *
+ * [in]    value[0].a	    Type of memory one of
+ *			    OPTEE_RPC_SHM_TYPE_* below
+ * [in]    value[0].b	    Requested size
+ * [in]    value[0].c	    Required alignment
+ * [out]   memref[0]	    Buffer
+ */
+#define OPTEE_RPC_CMD_SHM_ALLOC		6
+/* Memory that can be shared with a non-secure user space application */
+#define OPTEE_RPC_SHM_TYPE_APPL		0
+/* Memory only shared with non-secure kernel */
+#define OPTEE_RPC_SHM_TYPE_KERNEL	1
+
+/*
+ * Free shared memory previously allocated with OPTEE_RPC_CMD_SHM_ALLOC
+ *
+ * [in]     value[0].a	    Type of memory one of
+ *			    OPTEE_RPC_SHM_TYPE_* above
+ * [in]     value[0].b	    Value of shared memory reference or cookie
+ */
+#define OPTEE_RPC_CMD_SHM_FREE		7
+
+/*
+ * Issue master requests (read and write operations) to an I2C chip.
+ *
+ * [in]     value[0].a	    Transfer mode (OPTEE_RPC_I2C_TRANSFER_*)
+ * [in]     value[0].b	    The I2C bus (a.k.a adapter).
+ *				16 bit field.
+ * [in]     value[0].c	    The I2C chip (a.k.a address).
+ *				16 bit field (either 7 or 10 bit effective).
+ * [in]     value[1].a	    The I2C master control flags (ie, 10 bit address).
+ *				16 bit field.
+ * [in/out] memref[2]	    Buffer used for data transfers.
+ * [out]    value[3].a	    Number of bytes transferred by the REE.
+ */
+#define OPTEE_RPC_CMD_I2C_TRANSFER	21
+
+/* I2C master transfer modes */
+#define OPTEE_RPC_I2C_TRANSFER_RD	0
+#define OPTEE_RPC_I2C_TRANSFER_WR	1
+
+/* I2C master control flags */
+#define OPTEE_RPC_I2C_FLAGS_TEN_BIT	BIT(0)
+
+/*
+ * Reset RPMB probing
+ *
+ * Releases an eventually already used RPMB devices and starts over searching
+ * for RPMB devices. Returns the kind of shared memory to use in subsequent
+ * OPTEE_RPC_CMD_RPMB_PROBE_NEXT and OPTEE_RPC_CMD_RPMB calls.
+ *
+ * [out]    value[0].a	    OPTEE_RPC_SHM_TYPE_*, the parameter for
+ *			    OPTEE_RPC_CMD_SHM_ALLOC
+ */
+#define OPTEE_RPC_CMD_RPMB_PROBE_RESET	22
+
+/*
+ * Probe next RPMB device
+ *
+ * [out]    value[0].a	    Type of RPMB device, OPTEE_RPC_RPMB_*
+ * [out]    value[0].b	    EXT CSD-slice 168 "RPMB Size"
+ * [out]    value[0].c	    EXT CSD-slice 222 "Reliable Write Sector Count"
+ * [out]    memref[1]       Buffer with the raw CID
+ */
+#define OPTEE_RPC_CMD_RPMB_PROBE_NEXT	23
+
+/* Type of RPMB device */
+#define OPTEE_RPC_RPMB_EMMC		0
+#define OPTEE_RPC_RPMB_UFS		1
+#define OPTEE_RPC_RPMB_NVME		2
+
+/*
+ * Replay Protected Memory Block access
+ *
+ * [in]     memref[0]	    Frames to device
+ * [out]    memref[1]	    Frames from device
+ */
+#define OPTEE_RPC_CMD_RPMB_FRAMES	24
+
+#endif /*__OPTEE_RPC_CMD_H*/
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c
index 3d0a7f2980..bdb2a9da74 100644
--- a/drivers/tee/optee/rpc.c
+++ b/drivers/tee/optee/rpc.c
@@ -7,10 +7,66 @@
 
 #include <linux/tee_drv.h>
 #include "optee_private.h"
+#include "optee_rpc_cmd.h"
+
+static void cmd_shm_alloc(struct tee_context *ctx, struct optee_msg_arg *arg)
+{
+	struct tee_shm *shm;
+
+	arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+	if (arg->num_params != 1 ||
+	    arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
+		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+		return;
+	}
+
+	shm = tee_shm_alloc_kernel_buf(ctx, arg->params[0].u.value.b);
+	if (IS_ERR(shm)) {
+		if (PTR_ERR(shm) == -ENOMEM)
+			arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+		else
+			arg->ret = TEEC_ERROR_GENERIC;
+		return;
+	}
+
+	arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
+			      OPTEE_MSG_ATTR_NONCONTIG;
+	arg->params[0].u.tmem.buf_ptr = virt_to_phys(shm->pages_list);
+	arg->params[0].u.tmem.size = shm->size;
+	arg->params[0].u.tmem.shm_ref = (ulong)shm;
+	arg->ret = TEEC_SUCCESS;
+}
+
+static void cmd_shm_free(struct optee_msg_arg *arg)
+{
+	arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+	if (arg->num_params != 1 ||
+	    arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
+		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+		return;
+	}
+
+	tee_shm_free((struct tee_shm *)(ulong)arg->params[0].u.value.b);
+	arg->ret = TEEC_SUCCESS;
+}
 
 void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee,
 		   struct optee_msg_arg *arg)
 {
-	pr_notice_once("optee: No supplicant or RPC handler for command 0x%x\n", arg->cmd);
-	arg->ret = TEEC_ERROR_NOT_SUPPORTED;
+	pr_debug("%s: receive RPC CMD: %d\n", __func__, arg->cmd);
+
+	switch (arg->cmd) {
+	case OPTEE_RPC_CMD_SHM_ALLOC:
+		cmd_shm_alloc(ctx, arg);
+		break;
+	case OPTEE_RPC_CMD_SHM_FREE:
+		cmd_shm_free(arg);
+		break;
+	default:
+		arg->ret = TEEC_ERROR_NOT_IMPLEMENTED;
+	}
+
+	arg->ret_origin = TEEC_ORIGIN_COMMS;
 }
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 354a94a2f2..aab8ebb186 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -301,7 +301,7 @@ static int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm)
 	struct tee_shm *shm_arg;
 	u64 *pages_list;
 	u64 ph_ptr;
-	int rc = 0;
+	int rc;
 
 	pages_list = optee_alloc_and_init_page_list(shm->kaddr, shm->size, &ph_ptr);
 	if (!pages_list)
@@ -314,7 +314,7 @@ static int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm)
 	msg_arg = optee_get_msg_arg(ctx, 1, &shm_arg);
 	if (IS_ERR(msg_arg)) {
 		rc = PTR_ERR(msg_arg);
-		goto free_pages_list;
+		goto err_free;
 	}
 
 	msg_arg->num_params = 1;
@@ -326,11 +326,20 @@ static int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm)
 	msg_arg->params->u.tmem.size = tee_shm_get_size(shm);
 
 	if (optee->ops->do_call_with_arg(ctx, msg_arg) ||
-	    msg_arg->ret != TEEC_SUCCESS)
+	    msg_arg->ret != TEEC_SUCCESS) {
 		rc = -EINVAL;
+		goto err_free_msg_arg;
+	}
+
+	optee_free_msg_arg(ctx, shm_arg);
+
+	shm->pages_list = pages_list;
 
+	return 0;
+
+err_free_msg_arg:
 	optee_free_msg_arg(ctx, shm_arg);
-free_pages_list:
+err_free:
 	free(pages_list);
 
 	return rc;
@@ -383,8 +392,7 @@ static int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
  *
  * Result of RPC is written back into @param.
  */
-static void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,
-			     void *page_list)
+static void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param)
 {
 	struct tee_device *teedev = ctx->teedev;
 	struct optee *optee = tee_get_drvdata(teedev);
@@ -448,7 +456,6 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx,
 {
 	struct optee *optee = tee_get_drvdata(ctx->teedev);
 	struct optee_rpc_param param = { .a0 = OPTEE_SMC_CALL_WITH_ARG };
-	void *page_list = NULL;
 
 	reg_pair_from_64(&param.a1, &param.a2, virt_to_phys(arg));
 	while (true) {
@@ -461,15 +468,12 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx,
 		optee->smc.invoke_fn(param.a0, param.a1, param.a2, param.a3,
 				     param.a4, param.a5, param.a6, param.a7, &res);
 
-		free(page_list);
-		page_list = NULL;
-
 		if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
 			param.a0 = res.a0;
 			param.a1 = res.a1;
 			param.a2 = res.a2;
 			param.a3 = res.a3;
-			optee_handle_rpc(ctx, &param, &page_list);
+			optee_handle_rpc(ctx, &param);
 		} else {
 			return res.a0;
 		}
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 9952608435..50ed086d0e 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -32,6 +32,7 @@ static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm)
 
 	teedev_ctx_put(shm->ctx);
 
+	kfree(shm->pages_list);
 	kfree(shm);
 
 	tee_device_put(teedev);
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 7289c3057a..e2c1042deb 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -194,6 +194,7 @@ struct tee_shm {
 	struct tee_context *ctx;
 	phys_addr_t paddr;
 	void *kaddr;
+	u64 *pages_list;
 	size_t size;
 	refcount_t refcount;
 	u32 flags;

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 7/9] tee: optee: implement RPMB support
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
                   ` (5 preceding siblings ...)
  2025-03-12 12:16 ` [PATCH 6/9] tee: optee: implement shared mem alloc/free RPC commands Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  2025-03-12 12:16 ` [PATCH 8/9] tee: optee: implement AVB named persistent values support Sascha Hauer
  2025-03-12 12:16 ` [PATCH 9/9] commands: add avb_pvalue command Sascha Hauer
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

This implements the OPTEE_RPC_CMD_RPMB RPC call. For data requests we
call into the MMC specific RPMB implementation.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/tee/optee/Makefile        |   1 +
 drivers/tee/optee/optee_private.h |  10 +++
 drivers/tee/optee/rpc.c           |   3 +
 drivers/tee/optee/rpmb.c          | 128 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 142 insertions(+)

diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
index 5e71af77ee..f68352aa4e 100644
--- a/drivers/tee/optee/Makefile
+++ b/drivers/tee/optee/Makefile
@@ -6,3 +6,4 @@ optee-objs += call.o
 optee-objs += rpc.o
 optee-objs += device.o
 optee-objs += smc_abi.o
+obj-$(CONFIG_MCI_MMC_RPMB) += rpmb.o
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index d739a6c609..bb9ac1b068 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -179,4 +179,14 @@ static inline void reg_pair_from_64(u32 *reg0, u32 *reg1, u64 val)
 /* Registration of the ABIs */
 int optee_smc_abi_register(void);
 
+#ifdef CONFIG_MCI_MMC_RPMB
+void optee_suppl_cmd_rpmb(struct tee_context *ctx, struct optee_msg_arg *arg);
+#else
+static inline void optee_suppl_cmd_rpmb(struct tee_context *ctx, struct optee_msg_arg *arg)
+{
+	pr_debug("OPTEE_MSG_RPC_CMD_RPMB not implemented\n");
+	arg->ret = TEEC_ERROR_NOT_IMPLEMENTED;
+}
+#endif
+
 #endif /*OPTEE_PRIVATE_H*/
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c
index bdb2a9da74..182a06ec91 100644
--- a/drivers/tee/optee/rpc.c
+++ b/drivers/tee/optee/rpc.c
@@ -64,6 +64,9 @@ void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee,
 	case OPTEE_RPC_CMD_SHM_FREE:
 		cmd_shm_free(arg);
 		break;
+	case OPTEE_RPC_CMD_RPMB:
+		optee_suppl_cmd_rpmb(ctx, arg);
+		break;
 	default:
 		arg->ret = TEEC_ERROR_NOT_IMPLEMENTED;
 	}
diff --git a/drivers/tee/optee/rpmb.c b/drivers/tee/optee/rpmb.c
new file mode 100644
index 0000000000..da115796f4
--- /dev/null
+++ b/drivers/tee/optee/rpmb.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2018 Linaro Limited
+ */
+
+#define pr_fmt(fmt)     "optee-rpmb: " fmt
+
+#include <mci.h>
+
+#include "optee_msg.h"
+#include "optee_private.h"
+
+/*
+ * Request and response definitions must be in sync with the secure side of
+ * OP-TEE.
+ */
+
+/* Request */
+struct rpmb_req {
+	u16 cmd;
+#define RPMB_CMD_DATA_REQ      0x00
+#define RPMB_CMD_GET_DEV_INFO  0x01
+	u16 dev_id;
+	u16 block_count;
+	/* Optional data frames (rpmb_data_frame) follow */
+};
+
+#define RPMB_REQ_DATA(req) ((void *)((struct rpmb_req *)(req) + 1))
+
+/* Response to device info request */
+struct rpmb_dev_info {
+	u8 cid[16];
+	u8 rpmb_size_mult;	/* EXT CSD-slice 168: RPMB Size */
+	u8 rel_wr_sec_c;	/* EXT CSD-slice 222: Reliable Write Sector */
+				/*                    Count */
+	u8 ret_code;
+#define RPMB_CMD_GET_DEV_INFO_RET_OK     0x00
+#define RPMB_CMD_GET_DEV_INFO_RET_ERROR  0x01
+};
+
+static u32 rpmb_get_dev_info(struct mci *mci, struct rpmb_dev_info *info)
+{
+	int i;
+
+	if (!mci->ext_csd)
+		return TEEC_ERROR_GENERIC;
+
+	for (i = 0; i < ARRAY_SIZE(mci->raw_cid); i++)
+		((u32 *) info->cid)[i] = cpu_to_be32(mci->raw_cid[i]);
+
+	info->rel_wr_sec_c = mci->ext_csd[222];
+	info->rpmb_size_mult = mci->ext_csd[168];
+	info->ret_code = RPMB_CMD_GET_DEV_INFO_RET_OK;
+
+	return TEEC_SUCCESS;
+}
+
+static u32 rpmb_process_request(struct tee_context *ctx, void *req,
+				ulong req_size, void *rsp, ulong rsp_size)
+{
+	struct rpmb_req *sreq = req;
+	struct mci *mci = mci_get_rpmb_dev();
+
+	if (req_size < sizeof(*sreq))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!mci)
+		return TEEC_ERROR_ITEM_NOT_FOUND;
+
+	switch (sreq->cmd) {
+	case RPMB_CMD_DATA_REQ:
+		if (mci_rpmb_route_frames(mci, RPMB_REQ_DATA(req),
+					  req_size - sizeof(struct rpmb_req),
+					  rsp, rsp_size))
+			return TEEC_ERROR_BAD_PARAMETERS;
+		return TEEC_SUCCESS;
+
+	case RPMB_CMD_GET_DEV_INFO:
+		if (rsp_size != sizeof(struct rpmb_dev_info)) {
+			pr_debug("Invalid req/rsp size\n");
+			return TEEC_ERROR_BAD_PARAMETERS;
+		}
+
+		/*
+		 * We do not have any way in barebox to associate a dev_id with a
+		 * corresponding eMMC device. For now we assume that only a single
+		 * eMMC is present in the system which is assumed to have dev_id 0.
+		 */
+		if (sreq->dev_id != 0) {
+			pr_err("Unexpected RPMB dev_id %u\n", sreq->dev_id);
+			return TEEC_ERROR_ITEM_NOT_FOUND;
+		}
+
+		return rpmb_get_dev_info(mci, rsp);
+
+	default:
+		pr_debug("Unsupported RPMB command: %d\n", sreq->cmd);
+		return TEEC_ERROR_BAD_PARAMETERS;
+	}
+}
+
+void optee_suppl_cmd_rpmb(struct tee_context *ctx, struct optee_msg_arg *arg)
+{
+	struct tee_shm *req_shm;
+	struct tee_shm *rsp_shm;
+	void *req_buf;
+	void *rsp_buf;
+	ulong req_size;
+	ulong rsp_size;
+
+	if (arg->num_params != 2 ||
+	    arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_RMEM_INPUT ||
+	    arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) {
+		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+		return;
+	}
+
+	req_shm = (struct tee_shm *)(ulong)arg->params[0].u.rmem.shm_ref;
+	req_buf = (u8 *)req_shm->kaddr + arg->params[0].u.rmem.offs;
+	req_size = arg->params[0].u.rmem.size;
+
+	rsp_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref;
+	rsp_buf = (u8 *)rsp_shm->kaddr + arg->params[1].u.rmem.offs;
+	rsp_size = arg->params[1].u.rmem.size;
+
+	arg->ret = rpmb_process_request(ctx, req_buf, req_size,
+					rsp_buf, rsp_size);
+}

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 8/9] tee: optee: implement AVB named persistent values support
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
                   ` (6 preceding siblings ...)
  2025-03-12 12:16 ` [PATCH 7/9] tee: optee: implement RPMB support Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  2025-03-12 12:16 ` [PATCH 9/9] commands: add avb_pvalue command Sascha Hauer
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

Android Verified Boot (AVB) 2.0 spec. revision 1.1 introduces support
for named persistent values that must be tamper evident and allows AVB
to store arbitrary key-value pairs.

While AVB itself is not implemented in barebox. this patch allows
barebox to access the persistent value store. This is useful on its
own and can also be used to test the RPMB access in barebox.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/tee/optee/Kconfig  |   9 +++
 drivers/tee/optee/Makefile |   1 +
 drivers/tee/optee/avb.c    | 189 +++++++++++++++++++++++++++++++++++++++++++++
 include/tee/avb.h          |   9 +++
 4 files changed, 208 insertions(+)

diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig
index 045be3cca4..805aba65ed 100644
--- a/drivers/tee/optee/Kconfig
+++ b/drivers/tee/optee/Kconfig
@@ -31,6 +31,15 @@ config OPTEE_DEVFS
 	  but it's useful for compiling libteeclient + optee_tests for
 	  use inside barebox to verify proper operation of CONFIG_OPTEE.
 
+config OPTEE_AVB_PERSISTENT_VALUES
+	bool "Android Verified Boot (AVB) persistent values support"
+	depends on OPTEE
+	help
+	  AVB 2.0 spec. revision 1.1 introduces support for named persistent values
+	  that must be tamper evident and allows AVB to store arbitrary key-value
+	  pairs. AVB itself is not implemented in barebox, but enabling this option
+	  allows barebox to use the AVB persistent value store.
+
 endif
 
 config OF_FIXUP_OPTEE
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
index f68352aa4e..1fbeb39fb8 100644
--- a/drivers/tee/optee/Makefile
+++ b/drivers/tee/optee/Makefile
@@ -7,3 +7,4 @@ optee-objs += rpc.o
 optee-objs += device.o
 optee-objs += smc_abi.o
 obj-$(CONFIG_MCI_MMC_RPMB) += rpmb.o
+obj-$(CONFIG_OPTEE_AVB_PERSISTENT_VALUES) += avb.o
diff --git a/drivers/tee/optee/avb.c b/drivers/tee/optee/avb.c
new file mode 100644
index 0000000000..0adbee6258
--- /dev/null
+++ b/drivers/tee/optee/avb.c
@@ -0,0 +1,189 @@
+#include <linux/types.h>
+#include <tee/avb.h>
+#include <linux/tee_drv.h>
+
+#include "optee_private.h"
+
+#define TA_AVB_UUID UUID_INIT(0x023f8f1a, 0x292a, 0x432b, \
+                      0x8f, 0xc4, 0xde, 0x84, 0x71, 0x35, 0x80, 0x67)
+#define TEE_PARAM_ATTR_TYPE_MEMREF_INOUT       7       /* input and output */
+#define TA_AVB_CMD_READ_PERSIST_VALUE     4
+#define TEE_PARAM_ATTR_TYPE_MEMREF_INPUT       5
+#define TA_AVB_CMD_WRITE_PERSIST_VALUE    5
+
+static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+	if (ver->impl_id == TEE_IMPL_ID_OPTEE)
+		return 1;
+	else
+		return 0;
+}
+
+int avb_read_persistent_value(const char *name, size_t buffer_size,
+			      u8 *out_buffer, size_t *out_num_bytes_read)
+{
+	const uuid_t avb_uuid = TA_AVB_UUID;
+	int rc = 0;
+	struct tee_shm *shm_name;
+	struct tee_shm *shm_buf;
+	struct tee_param param[2];
+	size_t name_size = strlen(name) + 1;
+	struct tee_ioctl_open_session_arg sess_arg = {};
+	struct tee_context *ctx = NULL;
+	struct tee_ioctl_invoke_arg arg;
+
+	ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+	if (IS_ERR(ctx))
+		return -ENODEV;
+
+	export_uuid(sess_arg.uuid, &avb_uuid);
+	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+	sess_arg.num_params = 0;
+
+	rc = tee_client_open_session(ctx, &sess_arg, NULL);
+	if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) {
+		pr_debug("%s device enumeration pseudo TA not found\n", __func__);
+		rc = 0;
+		goto out_ctx;
+	}
+
+	shm_name = tee_shm_alloc_kernel_buf(ctx, name_size);
+	if (IS_ERR(shm_name)) {
+		rc = -ENOMEM;
+		goto close_session;
+	}
+
+	shm_buf = tee_shm_alloc_kernel_buf(ctx, buffer_size);
+	if (IS_ERR(shm_buf)) {
+		rc = -ENOMEM;
+		goto free_name;
+	}
+
+	memcpy(shm_name->kaddr, name, name_size);
+
+	memset(param, 0, sizeof(param));
+	param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	param[0].u.memref.shm = shm_name;
+	param[0].u.memref.size = name_size;
+	param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
+	param[1].u.memref.shm = shm_buf;
+	param[1].u.memref.size = buffer_size;
+
+	arg.func = TA_AVB_CMD_READ_PERSIST_VALUE;
+	arg.session = sess_arg.session;
+	arg.num_params = 2;
+
+	rc = tee_client_invoke_func(ctx, &arg, param);
+	if (rc)
+		goto out;
+	switch (arg.ret) {
+	case TEEC_SUCCESS:
+		rc = 0;
+		break;
+	case TEEC_ERROR_ITEM_NOT_FOUND:
+		rc = -ENOENT;
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	if (rc)
+		goto out;
+
+	if (param[1].u.memref.size > buffer_size) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	*out_num_bytes_read = param[1].u.memref.size;
+
+	memcpy(out_buffer, shm_buf->kaddr, *out_num_bytes_read);
+
+out:
+	tee_shm_free(shm_buf);
+free_name:
+	tee_shm_free(shm_name);
+close_session:
+	tee_client_close_session(ctx, sess_arg.session);
+out_ctx:
+	tee_client_close_context(ctx);
+
+	return rc;
+}
+
+int avb_write_persistent_value(const char *name, size_t value_size,
+			       const u8 *value)
+{
+	const uuid_t avb_uuid = TA_AVB_UUID;
+	int rc = 0;
+	struct tee_shm *shm_name;
+	struct tee_shm *shm_buf;
+	struct tee_param param[2];
+	struct tee_ioctl_open_session_arg sess_arg = {};
+	struct tee_context *ctx = NULL;
+	size_t name_size = strlen(name) + 1;
+	struct tee_ioctl_invoke_arg inv_arg;
+
+	if (!value_size)
+		return -EINVAL;
+
+	ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+	if (IS_ERR(ctx))
+		return -ENODEV;
+
+	export_uuid(sess_arg.uuid, &avb_uuid);
+	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+	sess_arg.num_params = 0;
+
+	rc = tee_client_open_session(ctx, &sess_arg, NULL);
+	if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) {
+		pr_err("%s AVB TA not found\n", __func__);
+		goto out_ctx;
+	}
+
+	shm_name = tee_shm_alloc_kernel_buf(ctx, name_size);
+	if (IS_ERR(shm_name)) {
+		rc = -ENOMEM;
+		goto close_session;
+	}
+
+	shm_buf = tee_shm_alloc_kernel_buf(ctx, value_size);
+	if (IS_ERR(shm_buf)) {
+		rc = -ENOMEM;
+		goto free_name;
+	}
+
+	memcpy(shm_name->kaddr, name, name_size);
+	memcpy(shm_buf->kaddr, value, value_size);
+
+	memset(param, 0, sizeof(param));
+	param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	param[0].u.memref.shm = shm_name;
+	param[0].u.memref.size = name_size;
+	param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	param[1].u.memref.shm = shm_buf;
+	param[1].u.memref.size = value_size;
+
+	inv_arg.func = TA_AVB_CMD_WRITE_PERSIST_VALUE;
+	inv_arg.session = sess_arg.session;
+	inv_arg.num_params = 2;
+
+	rc = tee_client_invoke_func(ctx, &inv_arg, param);
+	if (rc)
+		goto out;
+	if (inv_arg.ret) {
+		pr_err("invoke func failed with 0x%08x\n", inv_arg.ret);
+		rc = -EIO;
+	}
+
+out:
+	tee_shm_free(shm_buf);
+free_name:
+	tee_shm_free(shm_name);
+close_session:
+	tee_client_close_session(ctx, sess_arg.session);
+out_ctx:
+	tee_client_close_context(ctx);
+
+	return rc;
+}
diff --git a/include/tee/avb.h b/include/tee/avb.h
new file mode 100644
index 0000000000..3873b5c59b
--- /dev/null
+++ b/include/tee/avb.h
@@ -0,0 +1,9 @@
+#ifndef TEE_AVB_H
+#define TEE_AVB_H
+
+int avb_write_persistent_value(const char *name, size_t value_size,
+			       const u8 *value);
+int avb_read_persistent_value(const char *name, size_t buffer_size,
+			      u8 *out_buffer, size_t *out_num_bytes_read);
+
+#endif /* TEE_AVB_H */

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 9/9] commands: add avb_pvalue command
  2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
                   ` (7 preceding siblings ...)
  2025-03-12 12:16 ` [PATCH 8/9] tee: optee: implement AVB named persistent values support Sascha Hauer
@ 2025-03-12 12:16 ` Sascha Hauer
  8 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2025-03-12 12:16 UTC (permalink / raw)
  To: open list:BAREBOX

Android Verified Boot (AVB( 2.0 spec. revision 1.1 introduces support
for named persistent values that must be tamper evident and allows AVB
to store arbitrary key-value pairs.

This patch introduces a command to access this variable store. Variables
can be read into a file or an environment variable or printed as
hexdump. Variables can be written from file content or a string from the
command line.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 commands/Kconfig      |  13 +++++
 commands/Makefile     |   1 +
 commands/avb_pvalue.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 152 insertions(+)

diff --git a/commands/Kconfig b/commands/Kconfig
index e41625e294..3d87ba5e09 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -2254,6 +2254,19 @@ config CMD_2048
 	help
 	  Console version of the game "2048" for GNU/Linux
 
+config CMD_AVB_PVALUE
+	depends on OPTEE_AVB_PERSISTENT_VALUES
+	tristate
+	prompt "avb_pvalue"
+	help
+	  The avb_pvalue command provides access to the Android Verified Boot (AVB)
+	  persistent value store.
+
+	  AVB 2.0 spec. revision 1.1 introduces support for named persistent values
+	  that must be tamper evident and allows AVB to store arbitrary key-value
+	  pairs.
+
+
 config CMD_BAREBOX_UPDATE
 	tristate
 	select BAREBOX_UPDATE
diff --git a/commands/Makefile b/commands/Makefile
index e152e4148b..7a635e8791 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -3,6 +3,7 @@
 obj-$(CONFIG_STDDEV)		+= stddev.o
 obj-$(CONFIG_CMD_DIGEST)	+= digest.o
 obj-$(CONFIG_COMPILE_HASH)	+= hashsum.o
+obj-$(CONFIG_CMD_AVB_PVALUE)	+= avb_pvalue.o
 obj-$(CONFIG_CMD_BOOTM)		+= bootm.o
 obj-$(CONFIG_CMD_UIMAGE)	+= uimage.o
 obj-$(CONFIG_CMD_LOADB)		+= loadb.o
diff --git a/commands/avb_pvalue.c b/commands/avb_pvalue.c
new file mode 100644
index 0000000000..adc44321fb
--- /dev/null
+++ b/commands/avb_pvalue.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <command.h>
+#include <getopt.h>
+#include <libfile.h>
+#include <fs.h>
+#include <xfuncs.h>
+#include <linux/sizes.h>
+#include <tee/avb.h>
+#include <linux/ctype.h>
+#include <environment.h>
+
+static int do_avb_pvalue(int argc, char *argv[])
+{
+	size_t out = 0x13;
+	void *buf = NULL;
+	int ret = 0, rc = COMMAND_ERROR;
+	int opt;
+	const char *write_varname = NULL, *read_varname = NULL;
+	void *val = NULL;
+	size_t size;
+	const char *filename = NULL;
+	const char *varname = NULL;
+	const int bufsize = SZ_8K;
+
+	while ((opt = getopt(argc, argv, "r:w:f:")) > 0) {
+		switch(opt) {
+		case 'r':
+			read_varname = optarg;
+			break;
+		case 'w':
+			write_varname = optarg;
+			break;
+		case 'f':
+			filename = optarg;
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (!read_varname && !write_varname)
+		return COMMAND_ERROR_USAGE;
+
+	if (read_varname && write_varname)
+		return COMMAND_ERROR_USAGE;
+
+	if (write_varname) {
+		if (argc >= 1)
+			val = argv[0];
+
+		if (filename) {
+			ret = read_file_2(filename, &size, &buf, FILESIZE_MAX);
+			if (ret) {
+				printf("Cannot read %s: %pe\n", read_varname, ERR_PTR(ret));
+				return COMMAND_ERROR;
+			}
+		} else {
+			if (!val)
+				return COMMAND_ERROR_USAGE;
+			size = strlen(val) + 1;
+			buf = xstrdup(val);
+
+		}
+		ret = avb_write_persistent_value(write_varname, size, buf);
+		if (ret) {
+			printf("Cannot write variable %s: %pe\n", read_varname, ERR_PTR(ret));
+			goto err;
+		}
+	}
+
+	if (read_varname) {
+		if (argc >= 1)
+			varname = argv[0];
+
+		buf = xzalloc(bufsize);
+
+		ret = avb_read_persistent_value(read_varname, SZ_8K, buf, &out);
+		if (ret) {
+			printf("Cannot read variable %s: %pe\n", read_varname, ERR_PTR(ret));
+			rc = COMMAND_ERROR;
+			goto err;
+		}
+
+		if (filename) {
+			ret = write_file(filename, buf, out);
+			if (ret) {
+				printf("Cannot write %s: %pe\n", filename, ERR_PTR(ret));
+				rc = COMMAND_ERROR;
+				goto err;
+			}
+		} else if (varname) {
+			unsigned char *str = buf;
+			int i;
+
+			str[bufsize - 1] = 0;
+	
+			for (i = 0; i < out; i++)
+				if (!isprint(str[i]))
+					break;
+
+			str[i] = 0;
+
+			setenv(varname, buf);
+		} else {
+			memory_display(buf, 0, out, 1, 0);
+		}
+	}
+
+	rc = 0;
+
+err:
+	free(buf);
+
+	return rc;
+}
+
+BAREBOX_CMD_HELP_START(avb_pvalue)
+BAREBOX_CMD_HELP_TEXT("This command provides access to the AVB persistent variable store.")
+BAREBOX_CMD_HELP_TEXT("usage:")
+BAREBOX_CMD_HELP_TEXT("avb_pvalue [OPTION]... [VARNAME/VALUE]")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-r <varname>",  "read variable <varname>. read value into [VARNAME] if given")
+BAREBOX_CMD_HELP_OPT ("-w <varname>",  "write variable <varname>. Set to [VALUE] if given")
+BAREBOX_CMD_HELP_OPT ("-f <file>",  "read/write value from/to file")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(avb_pvalue)
+	.cmd            = do_avb_pvalue,
+	BAREBOX_CMD_DESC("AVB persistent variable store")
+	BAREBOX_CMD_OPTS("[-rwf] [VARNAME/VALUE]")
+	BAREBOX_CMD_HELP(cmd_avb_pvalue_help)
+	BAREBOX_CMD_GROUP(CMD_GRP_CONSOLE)
+BAREBOX_CMD_END

-- 
2.39.5




^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-03-12 13:06 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-03-12 12:16 [PATCH 0/9] Add RPMB support Sascha Hauer
2025-03-12 12:16 ` [PATCH 1/9] mci: implement mci_set_blockcount() Sascha Hauer
2025-03-12 12:16 ` [PATCH 2/9] mci: export some functions for RPMB support Sascha Hauer
2025-03-12 12:16 ` [PATCH 3/9] mci: detect RPMB partitions Sascha Hauer
2025-03-12 12:16 ` [PATCH 4/9] mci: add RPMB support Sascha Hauer
2025-03-12 12:16 ` [PATCH 5/9] tee: optee: probe successfully even when no devices are found Sascha Hauer
2025-03-12 12:16 ` [PATCH 6/9] tee: optee: implement shared mem alloc/free RPC commands Sascha Hauer
2025-03-12 12:16 ` [PATCH 7/9] tee: optee: implement RPMB support Sascha Hauer
2025-03-12 12:16 ` [PATCH 8/9] tee: optee: implement AVB named persistent values support Sascha Hauer
2025-03-12 12:16 ` [PATCH 9/9] commands: add avb_pvalue command Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox