mbox series

[v4,0/4] Introduction of a remoteproc tee to load signed firmware

Message ID 20240308144708.62362-1-arnaud.pouliquen@foss.st.com
Headers show
Series Introduction of a remoteproc tee to load signed firmware | expand

Message

Arnaud POULIQUEN March 8, 2024, 2:47 p.m. UTC
Main updates from the previous version [1]:

- Remove the alternate boot sequence: rproc_alt_fw_boot()
- Introduce tee_rproc_parse_fw function
	- create a cached table as done inrproc_elf_load_rsc_table[2],
	- PR sent to OP-TEE to allow TA_RPROC_FW_CMD_LOAD_FW service 
	  re-entrance[3].
- Rework TEE_REMOTEPROC description in Kconfig
- Introduce proc::tee_interface

Patch commit messages list updates with more details

base-commit: 62210f7509e13a2caa7b080722a45229b8f17a0a

[1] https://lore.kernel.org/linux-arm-kernel/Zdjl6Z2ktTwi+oWp@p14s/T/#m53f994237dc984c5dbbe3c75d2c30fcfff8548a0
[2] https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_elf_loader.c#L326
[3] https://github.com/OP-TEE/optee_os/pull/6743


Description of the feature:

This series proposes the implementation of a remoteproc tee driver to
communicate with a TEE trusted application responsible for authenticating and
loading the remoteproc firmware image in an Arm secure context.

1) Principle:

The remoteproc tee driver provides services to communicate with the OP-TEE
trusted application running on the Trusted Execution Context (TEE).
The trusted application in TEE manages the remote processor lifecycle:

- authenticating and loading firmware images,
- isolating and securing the remote processor memories,
- supporting multi-firmware (e.g., TF-M + Zephyr on a Cortex-M33),
- managing the start and stop of the firmware by the TEE.

2) Format of the signed image:

Refer to:
https://github.com/OP-TEE/optee_os/blob/master/ta/remoteproc/src/remoteproc_core.c#L18-L57

3) OP-TEE trusted application API:

Refer to:
https://github.com/OP-TEE/optee_os/blob/master/ta/remoteproc/include/ta_remoteproc.h

4) OP-TEE signature script

Refer to:
https://github.com/OP-TEE/optee_os/blob/master/scripts/sign_rproc_fw.py

Example of usage:
sign_rproc_fw.py --in <fw1.elf> --in <fw2.elf> --out <signed_fw.sign> --key ${OP-TEE_PATH}/keys/default.pem


5) Impact on User space Application

No sysfs impact.the user only needs to provide the signed firmware image
instead of the ELF image.


For more information about the implementation, a presentation is available here
(note that the format of the signed image has evolved between the presentation
and the integration in OP-TEE).

https://resources.linaro.org/en/resource/6c5bGvZwUAjX56fvxthxds

Arnaud Pouliquen (4):
  remoteproc: Add TEE support
  dt-bindings: remoteproc: Add compatibility for TEE support
  remoteproc: stm32: Create sub-functions to request shutdown and
    release
  remoteproc: stm32: Add support of an OP-TEE TA to load the firmware

 .../bindings/remoteproc/st,stm32-rproc.yaml   |  51 +-
 drivers/remoteproc/Kconfig                    |  10 +
 drivers/remoteproc/Makefile                   |   1 +
 drivers/remoteproc/stm32_rproc.c              | 144 ++++--
 drivers/remoteproc/tee_remoteproc.c           | 434 ++++++++++++++++++
 include/linux/remoteproc.h                    |   4 +
 include/linux/tee_remoteproc.h                | 112 +++++
 7 files changed, 711 insertions(+), 45 deletions(-)
 create mode 100644 drivers/remoteproc/tee_remoteproc.c
 create mode 100644 include/linux/tee_remoteproc.h


base-commit: 62210f7509e13a2caa7b080722a45229b8f17a0a

Comments

Mathieu Poirier March 25, 2024, 4:46 p.m. UTC | #1
On Fri, Mar 08, 2024 at 03:47:05PM +0100, Arnaud Pouliquen wrote:
> Add a remoteproc TEE (Trusted Execution Environment) driver
> that will be probed by the TEE bus. If the associated Trusted
> application is supported on secure part this device offers a client

Device or driver?  I thought I touched on that before.

> interface to load a firmware in the secure part.
> This firmware could be authenticated by the secure trusted application.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> Updates from V3:
> - rework TEE_REMOTEPROC description in Kconfig
> - fix some namings
> - add tee_rproc_parse_fw  to support rproc_ops::parse_fw
> - add proc::tee_interface;
> - add rproc struct as parameter of the tee_rproc_register() function
> ---
>  drivers/remoteproc/Kconfig          |  10 +
>  drivers/remoteproc/Makefile         |   1 +
>  drivers/remoteproc/tee_remoteproc.c | 434 ++++++++++++++++++++++++++++
>  include/linux/remoteproc.h          |   4 +
>  include/linux/tee_remoteproc.h      | 112 +++++++
>  5 files changed, 561 insertions(+)
>  create mode 100644 drivers/remoteproc/tee_remoteproc.c
>  create mode 100644 include/linux/tee_remoteproc.h
> 
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index 48845dc8fa85..2cf1431b2b59 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -365,6 +365,16 @@ config XLNX_R5_REMOTEPROC
>  
>  	  It's safe to say N if not interested in using RPU r5f cores.
>  
> +
> +config TEE_REMOTEPROC
> +	tristate "remoteproc support by a TEE application"

s/remoteproc/Remoteproc

> +	depends on OPTEE
> +	help
> +	  Support a remote processor with a TEE application. The Trusted
> +	  Execution Context is responsible for loading the trusted firmware
> +	  image and managing the remote processor's lifecycle.
> +	  This can be either built-in or a loadable module.
> +
>  endif # REMOTEPROC
>  
>  endmenu
> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
> index 91314a9b43ce..fa8daebce277 100644
> --- a/drivers/remoteproc/Makefile
> +++ b/drivers/remoteproc/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_RCAR_REMOTEPROC)		+= rcar_rproc.o
>  obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
>  obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
>  obj-$(CONFIG_STM32_RPROC)		+= stm32_rproc.o
> +obj-$(CONFIG_TEE_REMOTEPROC)		+= tee_remoteproc.o
>  obj-$(CONFIG_TI_K3_DSP_REMOTEPROC)	+= ti_k3_dsp_remoteproc.o
>  obj-$(CONFIG_TI_K3_R5_REMOTEPROC)	+= ti_k3_r5_remoteproc.o
>  obj-$(CONFIG_XLNX_R5_REMOTEPROC)	+= xlnx_r5_remoteproc.o
> diff --git a/drivers/remoteproc/tee_remoteproc.c b/drivers/remoteproc/tee_remoteproc.c
> new file mode 100644
> index 000000000000..c855210e52e3
> --- /dev/null
> +++ b/drivers/remoteproc/tee_remoteproc.c
> @@ -0,0 +1,434 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) STMicroelectronics 2024 - All Rights Reserved
> + * Author: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> + */
> +
> +#include <linux/firmware.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/remoteproc.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.h>
> +#include <linux/tee_remoteproc.h>
> +
> +#include "remoteproc_internal.h"
> +
> +#define MAX_TEE_PARAM_ARRY_MEMBER	4
> +
> +/*
> + * Authentication of the firmware and load in the remote processor memory
> + *
> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> + * [in]	 params[1].memref:	buffer containing the image of the buffer
> + */
> +#define TA_RPROC_FW_CMD_LOAD_FW		1
> +
> +/*
> + * Start the remote processor
> + *
> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> + */
> +#define TA_RPROC_FW_CMD_START_FW	2
> +
> +/*
> + * Stop the remote processor
> + *
> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> + */
> +#define TA_RPROC_FW_CMD_STOP_FW		3
> +
> +/*
> + * Return the address of the resource table, or 0 if not found
> + * No check is done to verify that the address returned is accessible by
> + * the non secure context. If the resource table is loaded in a protected
> + * memory the access by the non secure context will lead to a data abort.
> + *
> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> + * [out]  params[1].value.a:	32bit LSB resource table memory address
> + * [out]  params[1].value.b:	32bit MSB resource table memory address
> + * [out]  params[2].value.a:	32bit LSB resource table memory size
> + * [out]  params[2].value.b:	32bit MSB resource table memory size
> + */
> +#define TA_RPROC_FW_CMD_GET_RSC_TABLE	4
> +
> +/*
> + * Return the address of the core dump
> + *
> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> + * [out] params[1].memref:	address of the core dump image if exist,
> + *				else return Null
> + */
> +#define TA_RPROC_FW_CMD_GET_COREDUMP	5
> +
> +struct tee_rproc_context {
> +	struct list_head sessions;
> +	struct tee_context *tee_ctx;
> +	struct device *dev;
> +};
> +
> +static struct tee_rproc_context *tee_rproc_ctx;
> +
> +static void tee_rproc_prepare_args(struct tee_rproc *trproc, int cmd,
> +				   struct tee_ioctl_invoke_arg *arg,
> +				   struct tee_param *param,
> +				   unsigned int num_params)
> +{
> +	memset(arg, 0, sizeof(*arg));
> +	memset(param, 0, MAX_TEE_PARAM_ARRY_MEMBER * sizeof(*param));
> +
> +	arg->func = cmd;
> +	arg->session = trproc->session_id;
> +	arg->num_params = num_params + 1;
> +
> +	param[0] = (struct tee_param) {
> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> +		.u.value.a = trproc->rproc_id,
> +	};
> +}
> +
> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> +	struct tee_ioctl_invoke_arg arg;
> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> +	struct tee_rproc *trproc = rproc->tee_interface;
> +	struct tee_shm *fw_shm;
> +	int ret;

Declarations in reverse ascending order here and everywhere in the driver.
Sometimes it is done properly, sometimes it isn't. 

> +
> +	if (!trproc)
> +		return -EINVAL;
> +
> +	fw_shm = tee_shm_register_kernel_buf(tee_rproc_ctx->tee_ctx, (void *)fw->data, fw->size);
> +	if (IS_ERR(fw_shm))
> +		return PTR_ERR(fw_shm);
> +
> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_LOAD_FW, &arg, param, 1);
> +
> +	/* Provide the address of the firmware image */
> +	param[1] = (struct tee_param) {
> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
> +		.u.memref = {
> +			.shm = fw_shm,
> +			.size = fw->size,
> +			.shm_offs = 0,
> +		},
> +	};
> +
> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(tee_rproc_ctx->dev,
> +			"TA_RPROC_FW_CMD_LOAD_FW invoke failed TEE err: %x, ret:%x\n",
> +			arg.ret, ret);
> +		if (!ret)
> +			ret = -EIO;
> +	}
> +
> +	tee_shm_free(fw_shm);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_load_fw);
> +
> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
> +{
> +	struct tee_ioctl_invoke_arg arg;
> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> +	struct tee_rproc *trproc = rproc->tee_interface;
> +	struct resource_table *rsc_table;
> +	int ret;
> +
> +	if (!trproc)
> +		return ERR_PTR(-EINVAL);
> +
> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_GET_RSC_TABLE, &arg, param, 2);
> +
> +	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> +	param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> +
> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(tee_rproc_ctx->dev,
> +			"TA_RPROC_FW_CMD_GET_RSC_TABLE invoke failed TEE err: %x, ret:%x\n",
> +			arg.ret, ret);
> +		return ERR_PTR(-EIO);
> +	}
> +
> +	*table_sz = param[2].u.value.a;
> +
> +	/* If the size is null no resource table defined in the image */
> +	if (!*table_sz)
> +		return NULL;
> +
> +	/* Store the resource table address that would be updated by the remote core. */
> +	rsc_table = ioremap_wc(param[1].u.value.a, *table_sz);
> +	if (IS_ERR_OR_NULL(rsc_table)) {
> +		dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %lld+%zx\n",
> +			param[1].u.value.a, *table_sz);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	return rsc_table;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_get_loaded_rsc_table);
> +
> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> +	struct tee_rproc *trproc = rproc->tee_interface;
> +	struct resource_table *rsc_table;
> +	size_t table_sz;
> +	int ret;
> +
> +	ret = tee_rproc_load_fw(rproc, fw);
> +	if (ret)
> +		return ret;
> +
> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
> +	if (IS_ERR(rsc_table))
> +		return PTR_ERR(rsc_table);
> +
> +	/* Create a copy of the resource table to have same behaviour than the elf loader. */
> +	rproc->cached_table = kmemdup(rsc_table, table_sz, GFP_KERNEL);
> +	if (!rproc->cached_table)
> +		return -ENOMEM;

Why not ->table_ptr and setting ->cached_table to NULL?

> +
> +	rproc->table_ptr = rproc->cached_table;
> +	rproc->table_sz = table_sz;
> +	trproc->rsc_table = rsc_table;

I really don't see why this is needed, please remove and use rproc->table_ptr
instead.

> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_parse_fw);
> +
> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
> +						       const struct firmware *fw)
> +{
> +	struct tee_rproc *trproc = rproc->tee_interface;
> +	struct resource_table *rsc_table;
> +	size_t table_sz;
> +
> +	if (!trproc)
> +		return ERR_PTR(-EINVAL);
> +
> +	/* Check if the resourse table has already been obtained in tee_rproc_parse_fw() */
> +	if (trproc->rsc_table)
> +		return trproc->rsc_table;

Again, why not simply use rproc->rsc_table?  This function should only return
the resource table that was set in tee_rproc_parse_fw(). 

> +
> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
> +	if (IS_ERR(rsc_table))
> +		return rsc_table;
> +
> +	rproc->table_sz = table_sz;
> +	trproc->rsc_table = rsc_table;
> +
> +	return rsc_table;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
> +
> +int tee_rproc_start(struct rproc *rproc)
> +{
> +	struct tee_ioctl_invoke_arg arg;
> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> +	struct tee_rproc *trproc = rproc->tee_interface;
> +	int ret;
> +
> +	if (!trproc)
> +		return -EINVAL;
> +
> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_START_FW, &arg, param, 0);
> +
> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(tee_rproc_ctx->dev,
> +			"TA_RPROC_FW_CMD_START_FW invoke failed TEE err: %x, ret:%x\n",
> +			arg.ret, ret);
> +		if (!ret)
> +			ret = -EIO;
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_start);
> +
> +int tee_rproc_stop(struct rproc *rproc)
> +{
> +	struct tee_ioctl_invoke_arg arg;
> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> +	struct tee_rproc *trproc = rproc->tee_interface;
> +	int ret;
> +
> +	if (!trproc)
> +		return -EINVAL;
> +
> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_STOP_FW, &arg, param, 0);
> +
> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(tee_rproc_ctx->dev,
> +			"TA_RPROC_FW_CMD_STOP_FW invoke failed TEE err: %x, ret:%x\n",
> +			arg.ret, ret);
> +		if (!ret)
> +			ret = -EIO;
> +	}
> +
> +	if (!rproc->table_ptr)
> +		return ret;
> +
> +	iounmap(trproc->rsc_table);
> +	trproc->rsc_table = NULL;
> +	rproc->table_ptr = NULL;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_stop);
> +
> +static const struct tee_client_device_id stm32_tee_rproc_id_table[] = {
> +	{UUID_INIT(0x80a4c275, 0x0a47, 0x4905,
> +		   0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
> +	{}
> +};
> +
> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, unsigned int rproc_id)
> +{
> +	struct tee_client_device *tee_device;
> +	struct tee_ioctl_open_session_arg sess_arg;
> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> +	struct tee_rproc *trproc;
> +	int ret;
> +
> +	/*
> +	 * Test if the device has been probed by the TEE bus. In case of failure, we ignore the
> +	 * reason. The bus could be not yet probed or the service not available in the secure
> +	 * firmware.The assumption in such a case is that the TEE remoteproc is not probed.
> +	 */
> +	if (!tee_rproc_ctx)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	trproc =  devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
> +	if (!trproc)
> +		return ERR_PTR(-ENOMEM);
> +
> +	tee_device = to_tee_client_device(tee_rproc_ctx->dev);
> +	memset(&sess_arg, 0, sizeof(sess_arg));
> +
> +	memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> +
> +	sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
> +	sess_arg.num_params = 1;
> +
> +	param[0] = (struct tee_param) {
> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> +		.u.value.a = rproc_id,
> +	};
> +
> +	ret = tee_client_open_session(tee_rproc_ctx->tee_ctx, &sess_arg, param);
> +	if (ret < 0 || sess_arg.ret != 0) {
> +		dev_err(dev, "tee_client_open_session failed, err: %x\n", sess_arg.ret);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	trproc->parent =  dev;
> +	trproc->rproc_id = rproc_id;
> +	trproc->session_id = sess_arg.session;
> +
> +	trproc->rproc = rproc;
> +	rproc->tee_interface = trproc;
> +
> +	list_add_tail(&trproc->node, &tee_rproc_ctx->sessions);
> +
> +	return trproc;

Once this function was called by a client, what prevents a user from unloading
the tee_remoteproc module and breaking everything?

> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_register);
> +
> +int tee_rproc_unregister(struct tee_rproc *trproc)
> +{

If you pass a struct_rproc instead of a struct tee_rproc there is no need for
tee_rproc::rproc, which is only ever used in this function.


> +	struct rproc *rproc = trproc->rproc;
> +	int ret;
> +
> +	ret = tee_client_close_session(tee_rproc_ctx->tee_ctx, trproc->session_id);
> +	if (ret < 0)
> +		dev_err(trproc->parent,	"tee_client_close_session failed, err: %x\n", ret);
> +
> +	list_del(&trproc->node);
> +	rproc->tee_interface = NULL;
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_unregister);
> +
> +static int tee_rproc_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> +{
> +	/* Today we support only the OP-TEE, could be extend to other tees */
> +	return (ver->impl_id == TEE_IMPL_ID_OPTEE);
> +}
> +
> +static int tee_rproc_probe(struct device *dev)
> +{
> +	struct tee_context *tee_ctx;
> +	int ret;
> +
> +	/* Open context with TEE driver */
> +	tee_ctx = tee_client_open_context(NULL, tee_rproc_ctx_match, NULL, NULL);
> +	if (IS_ERR(tee_ctx))
> +		return PTR_ERR(tee_ctx);
> +
> +	tee_rproc_ctx = devm_kzalloc(dev, sizeof(*tee_ctx), GFP_KERNEL);
> +	if (!tee_rproc_ctx) {
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
> +	tee_rproc_ctx->dev = dev;
> +	tee_rproc_ctx->tee_ctx = tee_ctx;
> +	INIT_LIST_HEAD(&tee_rproc_ctx->sessions);
> +
> +	return 0;
> +err:
> +	tee_client_close_context(tee_ctx);
> +
> +	return ret;
> +}
> +
> +static int tee_rproc_remove(struct device *dev)
> +{
> +	struct tee_rproc *entry, *tmp;
> +
> +	list_for_each_entry_safe(entry, tmp, &tee_rproc_ctx->sessions, node) {
> +		tee_client_close_session(tee_rproc_ctx->tee_ctx, entry->session_id);
> +		list_del(&entry->node);
> +		if (entry->rsc_table)
> +			iounmap(entry->rsc_table);
> +		kfree(entry);
> +	}
> +
> +	tee_client_close_context(tee_rproc_ctx->tee_ctx);
> +
> +	return 0;
> +}
> +
> +MODULE_DEVICE_TABLE(tee, stm32_tee_rproc_id_table);
> +
> +static struct tee_client_driver tee_rproc_fw_driver = {
> +	.id_table	= stm32_tee_rproc_id_table,
> +	.driver		= {
> +		.name		= KBUILD_MODNAME,
> +		.bus		= &tee_bus_type,
> +		.probe		= tee_rproc_probe,
> +		.remove		= tee_rproc_remove,
> +	},
> +};
> +
> +static int __init tee_rproc_fw_mod_init(void)
> +{
> +	return driver_register(&tee_rproc_fw_driver.driver);
> +}
> +
> +static void __exit tee_rproc_fw_mod_exit(void)
> +{
> +	driver_unregister(&tee_rproc_fw_driver.driver);
> +}
> +
> +module_init(tee_rproc_fw_mod_init);
> +module_exit(tee_rproc_fw_mod_exit);
> +
> +MODULE_DESCRIPTION(" TEE remote processor control driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index b4795698d8c2..8b678009e481 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -503,6 +503,8 @@ enum rproc_features {
>  	RPROC_MAX_FEATURES,
>  };
>  
> +struct tee_rproc;
> +
>  /**
>   * struct rproc - represents a physical remote processor device
>   * @node: list node of this rproc object
> @@ -545,6 +547,7 @@ enum rproc_features {
>   * @cdev: character device of the rproc
>   * @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release
>   * @features: indicate remoteproc features
> + * @tee_interface: pointer to the remoteproc tee context
>   */
>  struct rproc {
>  	struct list_head node;
> @@ -586,6 +589,7 @@ struct rproc {
>  	struct cdev cdev;
>  	bool cdev_put_on_release;
>  	DECLARE_BITMAP(features, RPROC_MAX_FEATURES);
> +	struct tee_rproc *tee_interface;
>  };
>  
>  /**
> diff --git a/include/linux/tee_remoteproc.h b/include/linux/tee_remoteproc.h
> new file mode 100644
> index 000000000000..571e47190d02
> --- /dev/null
> +++ b/include/linux/tee_remoteproc.h
> @@ -0,0 +1,112 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright(c) 2024 STMicroelectronics - All Rights Reserved
> + */
> +
> +#ifndef TEE_REMOTEPROC_H
> +#define TEE_REMOTEPROC_H
> +
> +#include <linux/tee_drv.h>
> +#include <linux/firmware.h>
> +#include <linux/remoteproc.h>
> +
> +struct rproc;
> +
> +/**
> + * struct tee_rproc - TEE remoteproc structure
> + * @node:		Reference in list
> + * @rproc:		Remoteproc reference
> + * @parent:		Parent device
> + * @rproc_id:		Identifier of the target firmware
> + * @session_id:		TEE session identifier
> + * @rsc_table:		Resource table virtual address.
> + */
> +struct tee_rproc {
> +	struct list_head node;
> +	struct rproc *rproc;
> +	struct device *parent;
> +	u32 rproc_id;
> +	u32 session_id;
> +	struct resource_table *rsc_table;
> +};
> +
> +#if IS_REACHABLE(CONFIG_TEE_REMOTEPROC)
> +
> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
> +				     unsigned int rproc_id);
> +int tee_rproc_unregister(struct tee_rproc *trproc);
> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw);
> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw);
> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz);
> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
> +						       const struct firmware *fw);
> +int tee_rproc_start(struct rproc *rproc);
> +int tee_rproc_stop(struct rproc *rproc);
> +
> +#else
> +
> +static inline struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
> +						   unsigned int rproc_id)
> +{
> +	return ERR_PTR(-ENODEV);
> +}
> +
> +static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline int tee_rproc_unregister(struct tee_rproc *trproc)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline int tee_rproc_load_fw(struct rproc *rproc,  const struct firmware *fw)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline int tee_rproc_start(struct rproc *rproc)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline int tee_rproc_stop(struct rproc *rproc)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline struct resource_table *
> +tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return NULL;
> +}
> +
> +static inline struct resource_table *
> +tee_rproc_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return NULL;
> +}
> +#endif /* CONFIG_TEE_REMOTEPROC */
> +#endif /* TEE_REMOTEPROC_H */
> -- 
> 2.25.1
>
Mathieu Poirier March 25, 2024, 4:48 p.m. UTC | #2
On Fri, Mar 08, 2024 at 03:47:07PM +0100, Arnaud Pouliquen wrote:
> To prepare for the support of TEE remoteproc, create sub-functions
> that can be used in both cases, with and without TEE support.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
>  drivers/remoteproc/stm32_rproc.c | 84 +++++++++++++++++++-------------
>  1 file changed, 51 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
> index 88623df7d0c3..8cd838df4e92 100644
> --- a/drivers/remoteproc/stm32_rproc.c
> +++ b/drivers/remoteproc/stm32_rproc.c
> @@ -209,6 +209,54 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name)
>  	return -EINVAL;
>  }
>  
> +static void stm32_rproc_request_shutdown(struct rproc *rproc)
> +{
> +	struct stm32_rproc *ddata = rproc->priv;
> +	int err, dummy_data, idx;
> +
> +	/* Request shutdown of the remote processor */
> +	if (rproc->state != RPROC_OFFLINE && rproc->state != RPROC_CRASHED) {
> +		idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN);
> +		if (idx >= 0 && ddata->mb[idx].chan) {
> +			/* A dummy data is sent to allow to block on transmit. */
> +			err = mbox_send_message(ddata->mb[idx].chan,
> +						&dummy_data);

Why is this changed from the original implementation?

> +			if (err < 0)
> +				dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
> +		}
> +	}
> +}
> +
> +static int stm32_rproc_release(struct rproc *rproc)
> +{
> +	struct stm32_rproc *ddata = rproc->priv;
> +	unsigned int err = 0;
> +
> +	/* To allow platform Standby power mode, set remote proc Deep Sleep. */
> +	if (ddata->pdds.map) {
> +		err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg,
> +					 ddata->pdds.mask, 1);
> +		if (err) {
> +			dev_err(&rproc->dev, "failed to set pdds\n");
> +			return err;
> +		}
> +	}
> +
> +	/* Update coprocessor state to OFF if available. */
> +	if (ddata->m4_state.map) {
> +		err = regmap_update_bits(ddata->m4_state.map,
> +					 ddata->m4_state.reg,
> +					 ddata->m4_state.mask,
> +					 M4_STATE_OFF);
> +		if (err) {
> +			dev_err(&rproc->dev, "failed to set copro state\n");
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static int stm32_rproc_prepare(struct rproc *rproc)
>  {
>  	struct device *dev = rproc->dev.parent;
> @@ -519,17 +567,9 @@ static int stm32_rproc_detach(struct rproc *rproc)
>  static int stm32_rproc_stop(struct rproc *rproc)
>  {
>  	struct stm32_rproc *ddata = rproc->priv;
> -	int err, idx;
> +	int err;
>  
> -	/* request shutdown of the remote processor */
> -	if (rproc->state != RPROC_OFFLINE && rproc->state != RPROC_CRASHED) {
> -		idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN);
> -		if (idx >= 0 && ddata->mb[idx].chan) {
> -			err = mbox_send_message(ddata->mb[idx].chan, "detach");
> -			if (err < 0)
> -				dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
> -		}
> -	}
> +	stm32_rproc_request_shutdown(rproc);
>  
>  	err = stm32_rproc_set_hold_boot(rproc, true);
>  	if (err)
> @@ -541,29 +581,7 @@ static int stm32_rproc_stop(struct rproc *rproc)
>  		return err;
>  	}
>  
> -	/* to allow platform Standby power mode, set remote proc Deep Sleep */
> -	if (ddata->pdds.map) {
> -		err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg,
> -					 ddata->pdds.mask, 1);
> -		if (err) {
> -			dev_err(&rproc->dev, "failed to set pdds\n");
> -			return err;
> -		}
> -	}
> -
> -	/* update coprocessor state to OFF if available */
> -	if (ddata->m4_state.map) {
> -		err = regmap_update_bits(ddata->m4_state.map,
> -					 ddata->m4_state.reg,
> -					 ddata->m4_state.mask,
> -					 M4_STATE_OFF);
> -		if (err) {
> -			dev_err(&rproc->dev, "failed to set copro state\n");
> -			return err;
> -		}
> -	}
> -
> -	return 0;
> +	return stm32_rproc_release(rproc);
>  }
>  
>  static void stm32_rproc_kick(struct rproc *rproc, int vqid)
> -- 
> 2.25.1
>
Mathieu Poirier March 25, 2024, 4:51 p.m. UTC | #3
On Fri, Mar 08, 2024 at 03:47:08PM +0100, Arnaud Pouliquen wrote:
> The new TEE remoteproc device is used to manage remote firmware in a
> secure, trusted context. The 'st,stm32mp1-m4-tee' compatibility is
> introduced to delegate the loading of the firmware to the trusted
> execution context. In such cases, the firmware should be signed and
> adhere to the image format defined by the TEE.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> Updates from V3:
> - remove support of the attach use case. Will be addressed in a separate
>   thread,
> - add st_rproc_tee_ops::parse_fw ops,
> - inverse call of devm_rproc_alloc()and tee_rproc_register() to manage cross
>   reference between the rproc struct and the tee_rproc struct in tee_rproc.c.
> ---
>  drivers/remoteproc/stm32_rproc.c | 60 +++++++++++++++++++++++++++++---
>  1 file changed, 56 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
> index 8cd838df4e92..13df33c78aa2 100644
> --- a/drivers/remoteproc/stm32_rproc.c
> +++ b/drivers/remoteproc/stm32_rproc.c
> @@ -20,6 +20,7 @@
>  #include <linux/remoteproc.h>
>  #include <linux/reset.h>
>  #include <linux/slab.h>
> +#include <linux/tee_remoteproc.h>
>  #include <linux/workqueue.h>
>  
>  #include "remoteproc_internal.h"
> @@ -49,6 +50,9 @@
>  #define M4_STATE_STANDBY	4
>  #define M4_STATE_CRASH		5
>  
> +/* Remote processor unique identifier aligned with the Trusted Execution Environment definitions */

Why is this the case?  At least from the kernel side it is possible to call
tee_rproc_register() with any kind of value, why is there a need to be any
kind of alignment with the TEE?

> +#define STM32_MP1_M4_PROC_ID    0
> +
>  struct stm32_syscon {
>  	struct regmap *map;
>  	u32 reg;
> @@ -257,6 +261,19 @@ static int stm32_rproc_release(struct rproc *rproc)
>  	return 0;
>  }
>  
> +static int stm32_rproc_tee_stop(struct rproc *rproc)
> +{
> +	int err;
> +
> +	stm32_rproc_request_shutdown(rproc);
> +
> +	err = tee_rproc_stop(rproc);
> +	if (err)
> +		return err;
> +
> +	return stm32_rproc_release(rproc);
> +}
> +
>  static int stm32_rproc_prepare(struct rproc *rproc)
>  {
>  	struct device *dev = rproc->dev.parent;
> @@ -693,8 +710,19 @@ static const struct rproc_ops st_rproc_ops = {
>  	.get_boot_addr	= rproc_elf_get_boot_addr,
>  };
>  
> +static const struct rproc_ops st_rproc_tee_ops = {
> +	.prepare	= stm32_rproc_prepare,
> +	.start		= tee_rproc_start,
> +	.stop		= stm32_rproc_tee_stop,
> +	.kick		= stm32_rproc_kick,
> +	.load		= tee_rproc_load_fw,
> +	.parse_fw	= tee_rproc_parse_fw,
> +	.find_loaded_rsc_table = tee_rproc_find_loaded_rsc_table,
> +};
> +
>  static const struct of_device_id stm32_rproc_match[] = {
> -	{ .compatible = "st,stm32mp1-m4" },
> +	{.compatible = "st,stm32mp1-m4",},
> +	{.compatible = "st,stm32mp1-m4-tee",},
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, stm32_rproc_match);
> @@ -853,6 +881,7 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>  	struct device *dev = &pdev->dev;
>  	struct stm32_rproc *ddata;
>  	struct device_node *np = dev->of_node;
> +	struct tee_rproc *trproc = NULL;
>  	struct rproc *rproc;
>  	unsigned int state;
>  	int ret;
> @@ -861,9 +890,26 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
> -	if (!rproc)
> -		return -ENOMEM;
> +	if (of_device_is_compatible(np, "st,stm32mp1-m4-tee")) {
> +		/*
> +		 * Delegate the firmware management to the secure context.
> +		 * The firmware loaded has to be signed.
> +		 */
> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
> +		if (!rproc)
> +			return -ENOMEM;
> +
> +		trproc = tee_rproc_register(dev, rproc, STM32_MP1_M4_PROC_ID);
> +		if (IS_ERR(trproc)) {
> +			dev_err_probe(dev, PTR_ERR(trproc),
> +				      "signed firmware not supported by TEE\n");
> +			return PTR_ERR(trproc);
> +		}
> +	} else {
> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
> +		if (!rproc)
> +			return -ENOMEM;
> +	}
>  
>  	ddata = rproc->priv;
>  
> @@ -915,6 +961,9 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>  		dev_pm_clear_wake_irq(dev);
>  		device_init_wakeup(dev, false);
>  	}
> +	if (trproc)

        if (rproc->tee_interface)


I am done reviewing this set.

Thanks,
Mathieu

> +		tee_rproc_unregister(trproc);
> +
>  	return ret;
>  }
>  
> @@ -935,6 +984,9 @@ static void stm32_rproc_remove(struct platform_device *pdev)
>  		dev_pm_clear_wake_irq(dev);
>  		device_init_wakeup(dev, false);
>  	}
> +	if (rproc->tee_interface)
> +		tee_rproc_unregister(rproc->tee_interface);
> +
>  }
>  
>  static int stm32_rproc_suspend(struct device *dev)
> -- 
> 2.25.1
>
Arnaud POULIQUEN March 26, 2024, 7:18 p.m. UTC | #4
Hello Mathieu,

On 3/25/24 17:46, Mathieu Poirier wrote:
> On Fri, Mar 08, 2024 at 03:47:05PM +0100, Arnaud Pouliquen wrote:
>> Add a remoteproc TEE (Trusted Execution Environment) driver
>> that will be probed by the TEE bus. If the associated Trusted
>> application is supported on secure part this device offers a client
> 
> Device or driver?  I thought I touched on that before.

Right, I changed the first instance and missed this one

> 
>> interface to load a firmware in the secure part.
>> This firmware could be authenticated by the secure trusted application.
>>
>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>> ---
>> Updates from V3:
>> - rework TEE_REMOTEPROC description in Kconfig
>> - fix some namings
>> - add tee_rproc_parse_fw  to support rproc_ops::parse_fw
>> - add proc::tee_interface;
>> - add rproc struct as parameter of the tee_rproc_register() function
>> ---
>>  drivers/remoteproc/Kconfig          |  10 +
>>  drivers/remoteproc/Makefile         |   1 +
>>  drivers/remoteproc/tee_remoteproc.c | 434 ++++++++++++++++++++++++++++
>>  include/linux/remoteproc.h          |   4 +
>>  include/linux/tee_remoteproc.h      | 112 +++++++
>>  5 files changed, 561 insertions(+)
>>  create mode 100644 drivers/remoteproc/tee_remoteproc.c
>>  create mode 100644 include/linux/tee_remoteproc.h
>>
>> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
>> index 48845dc8fa85..2cf1431b2b59 100644
>> --- a/drivers/remoteproc/Kconfig
>> +++ b/drivers/remoteproc/Kconfig
>> @@ -365,6 +365,16 @@ config XLNX_R5_REMOTEPROC
>>  
>>  	  It's safe to say N if not interested in using RPU r5f cores.
>>  
>> +
>> +config TEE_REMOTEPROC
>> +	tristate "remoteproc support by a TEE application"
> 
> s/remoteproc/Remoteproc
> 
>> +	depends on OPTEE
>> +	help
>> +	  Support a remote processor with a TEE application. The Trusted
>> +	  Execution Context is responsible for loading the trusted firmware
>> +	  image and managing the remote processor's lifecycle.
>> +	  This can be either built-in or a loadable module.
>> +
>>  endif # REMOTEPROC
>>  
>>  endmenu
>> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
>> index 91314a9b43ce..fa8daebce277 100644
>> --- a/drivers/remoteproc/Makefile
>> +++ b/drivers/remoteproc/Makefile
>> @@ -36,6 +36,7 @@ obj-$(CONFIG_RCAR_REMOTEPROC)		+= rcar_rproc.o
>>  obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
>>  obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
>>  obj-$(CONFIG_STM32_RPROC)		+= stm32_rproc.o
>> +obj-$(CONFIG_TEE_REMOTEPROC)		+= tee_remoteproc.o
>>  obj-$(CONFIG_TI_K3_DSP_REMOTEPROC)	+= ti_k3_dsp_remoteproc.o
>>  obj-$(CONFIG_TI_K3_R5_REMOTEPROC)	+= ti_k3_r5_remoteproc.o
>>  obj-$(CONFIG_XLNX_R5_REMOTEPROC)	+= xlnx_r5_remoteproc.o
>> diff --git a/drivers/remoteproc/tee_remoteproc.c b/drivers/remoteproc/tee_remoteproc.c
>> new file mode 100644
>> index 000000000000..c855210e52e3
>> --- /dev/null
>> +++ b/drivers/remoteproc/tee_remoteproc.c
>> @@ -0,0 +1,434 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (C) STMicroelectronics 2024 - All Rights Reserved
>> + * Author: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>> + */
>> +
>> +#include <linux/firmware.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/remoteproc.h>
>> +#include <linux/slab.h>
>> +#include <linux/tee_drv.h>
>> +#include <linux/tee_remoteproc.h>
>> +
>> +#include "remoteproc_internal.h"
>> +
>> +#define MAX_TEE_PARAM_ARRY_MEMBER	4
>> +
>> +/*
>> + * Authentication of the firmware and load in the remote processor memory
>> + *
>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>> + * [in]	 params[1].memref:	buffer containing the image of the buffer
>> + */
>> +#define TA_RPROC_FW_CMD_LOAD_FW		1
>> +
>> +/*
>> + * Start the remote processor
>> + *
>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>> + */
>> +#define TA_RPROC_FW_CMD_START_FW	2
>> +
>> +/*
>> + * Stop the remote processor
>> + *
>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>> + */
>> +#define TA_RPROC_FW_CMD_STOP_FW		3
>> +
>> +/*
>> + * Return the address of the resource table, or 0 if not found
>> + * No check is done to verify that the address returned is accessible by
>> + * the non secure context. If the resource table is loaded in a protected
>> + * memory the access by the non secure context will lead to a data abort.
>> + *
>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>> + * [out]  params[1].value.a:	32bit LSB resource table memory address
>> + * [out]  params[1].value.b:	32bit MSB resource table memory address
>> + * [out]  params[2].value.a:	32bit LSB resource table memory size
>> + * [out]  params[2].value.b:	32bit MSB resource table memory size
>> + */
>> +#define TA_RPROC_FW_CMD_GET_RSC_TABLE	4
>> +
>> +/*
>> + * Return the address of the core dump
>> + *
>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>> + * [out] params[1].memref:	address of the core dump image if exist,
>> + *				else return Null
>> + */
>> +#define TA_RPROC_FW_CMD_GET_COREDUMP	5
>> +
>> +struct tee_rproc_context {
>> +	struct list_head sessions;
>> +	struct tee_context *tee_ctx;
>> +	struct device *dev;
>> +};
>> +
>> +static struct tee_rproc_context *tee_rproc_ctx;
>> +
>> +static void tee_rproc_prepare_args(struct tee_rproc *trproc, int cmd,
>> +				   struct tee_ioctl_invoke_arg *arg,
>> +				   struct tee_param *param,
>> +				   unsigned int num_params)
>> +{
>> +	memset(arg, 0, sizeof(*arg));
>> +	memset(param, 0, MAX_TEE_PARAM_ARRY_MEMBER * sizeof(*param));
>> +
>> +	arg->func = cmd;
>> +	arg->session = trproc->session_id;
>> +	arg->num_params = num_params + 1;
>> +
>> +	param[0] = (struct tee_param) {
>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
>> +		.u.value.a = trproc->rproc_id,
>> +	};
>> +}
>> +
>> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
>> +{
>> +	struct tee_ioctl_invoke_arg arg;
>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>> +	struct tee_rproc *trproc = rproc->tee_interface;
>> +	struct tee_shm *fw_shm;
>> +	int ret;
> 
> Declarations in reverse ascending order here and everywhere in the driver.
> Sometimes it is done properly, sometimes it isn't. 
> 
>> +
>> +	if (!trproc)
>> +		return -EINVAL;
>> +
>> +	fw_shm = tee_shm_register_kernel_buf(tee_rproc_ctx->tee_ctx, (void *)fw->data, fw->size);
>> +	if (IS_ERR(fw_shm))
>> +		return PTR_ERR(fw_shm);
>> +
>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_LOAD_FW, &arg, param, 1);
>> +
>> +	/* Provide the address of the firmware image */
>> +	param[1] = (struct tee_param) {
>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
>> +		.u.memref = {
>> +			.shm = fw_shm,
>> +			.size = fw->size,
>> +			.shm_offs = 0,
>> +		},
>> +	};
>> +
>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
>> +	if (ret < 0 || arg.ret != 0) {
>> +		dev_err(tee_rproc_ctx->dev,
>> +			"TA_RPROC_FW_CMD_LOAD_FW invoke failed TEE err: %x, ret:%x\n",
>> +			arg.ret, ret);
>> +		if (!ret)
>> +			ret = -EIO;
>> +	}
>> +
>> +	tee_shm_free(fw_shm);
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(tee_rproc_load_fw);
>> +
>> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
>> +{
>> +	struct tee_ioctl_invoke_arg arg;
>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>> +	struct tee_rproc *trproc = rproc->tee_interface;
>> +	struct resource_table *rsc_table;
>> +	int ret;
>> +
>> +	if (!trproc)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_GET_RSC_TABLE, &arg, param, 2);
>> +
>> +	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
>> +	param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
>> +
>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
>> +	if (ret < 0 || arg.ret != 0) {
>> +		dev_err(tee_rproc_ctx->dev,
>> +			"TA_RPROC_FW_CMD_GET_RSC_TABLE invoke failed TEE err: %x, ret:%x\n",
>> +			arg.ret, ret);
>> +		return ERR_PTR(-EIO);
>> +	}
>> +
>> +	*table_sz = param[2].u.value.a;
>> +
>> +	/* If the size is null no resource table defined in the image */
>> +	if (!*table_sz)
>> +		return NULL;
>> +
>> +	/* Store the resource table address that would be updated by the remote core. */
>> +	rsc_table = ioremap_wc(param[1].u.value.a, *table_sz);
>> +	if (IS_ERR_OR_NULL(rsc_table)) {
>> +		dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %lld+%zx\n",
>> +			param[1].u.value.a, *table_sz);
>> +		return ERR_PTR(-ENOMEM);
>> +	}
>> +
>> +	return rsc_table;
>> +}
>> +EXPORT_SYMBOL_GPL(tee_rproc_get_loaded_rsc_table);
>> +
>> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
>> +{
>> +	struct tee_rproc *trproc = rproc->tee_interface;
>> +	struct resource_table *rsc_table;
>> +	size_t table_sz;
>> +	int ret;
>> +
>> +	ret = tee_rproc_load_fw(rproc, fw);
>> +	if (ret)
>> +		return ret;
>> +
>> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
>> +	if (IS_ERR(rsc_table))
>> +		return PTR_ERR(rsc_table);
>> +
>> +	/* Create a copy of the resource table to have same behaviour than the elf loader. */
>> +	rproc->cached_table = kmemdup(rsc_table, table_sz, GFP_KERNEL);
>> +	if (!rproc->cached_table)
>> +		return -ENOMEM;
> 
> Why not ->table_ptr and setting ->cached_table to NULL?

It was my plan preparing this version. But during implementarion it looks
to me that having exactly same behavior than the ELF loader would be
simpler to maintain the remoteproc avoiding to update in the remoteproc core
to manage for the cached resource table (see also my comment below abourt recovery)
That why I propose this implementation

That said what you proposal should also work (with some updates in
remoteproc_core for the management of the cached table).

So please just comfirm your preference.

> 
>> +
>> +	rproc->table_ptr = rproc->cached_table;
>> +	rproc->table_sz = table_sz;
>> +	trproc->rsc_table = rsc_table;
> 
> I really don't see why this is needed, please remove and use rproc->table_ptr
> instead.

I need to store it for the iounmap in tee_rproc_remove.

> 
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(tee_rproc_parse_fw);
>> +
>> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
>> +						       const struct firmware *fw)
>> +{
>> +	struct tee_rproc *trproc = rproc->tee_interface;
>> +	struct resource_table *rsc_table;
>> +	size_t table_sz;
>> +
>> +	if (!trproc)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	/* Check if the resourse table has already been obtained in tee_rproc_parse_fw() */
>> +	if (trproc->rsc_table)
>> +		return trproc->rsc_table;
> 
> Again, why not simply use rproc->rsc_table?  This function should only return
> the resource table that was set in tee_rproc_parse_fw(). 

In case of recovery rproc->_rsc_table point to the cached table [1]
and we need to reapply the configuration in rproc_start() called during the
recovery[2]
[1]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1586
[2]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1287

> 
>> +
>> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
>> +	if (IS_ERR(rsc_table))
>> +		return rsc_table;
>> +
>> +	rproc->table_sz = table_sz;
>> +	trproc->rsc_table = rsc_table;
>> +
>> +	return rsc_table;
>> +}
>> +EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
>> +
>> +int tee_rproc_start(struct rproc *rproc)
>> +{
>> +	struct tee_ioctl_invoke_arg arg;
>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>> +	struct tee_rproc *trproc = rproc->tee_interface;
>> +	int ret;
>> +
>> +	if (!trproc)
>> +		return -EINVAL;
>> +
>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_START_FW, &arg, param, 0);
>> +
>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
>> +	if (ret < 0 || arg.ret != 0) {
>> +		dev_err(tee_rproc_ctx->dev,
>> +			"TA_RPROC_FW_CMD_START_FW invoke failed TEE err: %x, ret:%x\n",
>> +			arg.ret, ret);
>> +		if (!ret)
>> +			ret = -EIO;
>> +	}
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(tee_rproc_start);
>> +
>> +int tee_rproc_stop(struct rproc *rproc)
>> +{
>> +	struct tee_ioctl_invoke_arg arg;
>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>> +	struct tee_rproc *trproc = rproc->tee_interface;
>> +	int ret;
>> +
>> +	if (!trproc)
>> +		return -EINVAL;
>> +
>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_STOP_FW, &arg, param, 0);
>> +
>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
>> +	if (ret < 0 || arg.ret != 0) {
>> +		dev_err(tee_rproc_ctx->dev,
>> +			"TA_RPROC_FW_CMD_STOP_FW invoke failed TEE err: %x, ret:%x\n",
>> +			arg.ret, ret);
>> +		if (!ret)
>> +			ret = -EIO;
>> +	}
>> +
>> +	if (!rproc->table_ptr)
>> +		return ret;
>> +
>> +	iounmap(trproc->rsc_table);
>> +	trproc->rsc_table = NULL;
>> +	rproc->table_ptr = NULL;
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(tee_rproc_stop);
>> +
>> +static const struct tee_client_device_id stm32_tee_rproc_id_table[] = {
>> +	{UUID_INIT(0x80a4c275, 0x0a47, 0x4905,
>> +		   0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
>> +	{}
>> +};
>> +
>> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, unsigned int rproc_id)
>> +{
>> +	struct tee_client_device *tee_device;
>> +	struct tee_ioctl_open_session_arg sess_arg;
>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>> +	struct tee_rproc *trproc;
>> +	int ret;
>> +
>> +	/*
>> +	 * Test if the device has been probed by the TEE bus. In case of failure, we ignore the
>> +	 * reason. The bus could be not yet probed or the service not available in the secure
>> +	 * firmware.The assumption in such a case is that the TEE remoteproc is not probed.
>> +	 */
>> +	if (!tee_rproc_ctx)
>> +		return ERR_PTR(-EPROBE_DEFER);
>> +
>> +	trproc =  devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
>> +	if (!trproc)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	tee_device = to_tee_client_device(tee_rproc_ctx->dev);
>> +	memset(&sess_arg, 0, sizeof(sess_arg));
>> +
>> +	memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
>> +
>> +	sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
>> +	sess_arg.num_params = 1;
>> +
>> +	param[0] = (struct tee_param) {
>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
>> +		.u.value.a = rproc_id,
>> +	};
>> +
>> +	ret = tee_client_open_session(tee_rproc_ctx->tee_ctx, &sess_arg, param);
>> +	if (ret < 0 || sess_arg.ret != 0) {
>> +		dev_err(dev, "tee_client_open_session failed, err: %x\n", sess_arg.ret);
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	trproc->parent =  dev;
>> +	trproc->rproc_id = rproc_id;
>> +	trproc->session_id = sess_arg.session;
>> +
>> +	trproc->rproc = rproc;
>> +	rproc->tee_interface = trproc;
>> +
>> +	list_add_tail(&trproc->node, &tee_rproc_ctx->sessions);
>> +
>> +	return trproc;
> 
> Once this function was called by a client, what prevents a user from unloading
> the tee_remoteproc module and breaking everything?

Good point! seems better toremove the module build capability

Thanks,
Arnaud

> 
>> +}
>> +EXPORT_SYMBOL_GPL(tee_rproc_register);
>> +
>> +int tee_rproc_unregister(struct tee_rproc *trproc)
>> +{
> 
> If you pass a struct_rproc instead of a struct tee_rproc there is no need for
> tee_rproc::rproc, which is only ever used in this function.
> 
> 
>> +	struct rproc *rproc = trproc->rproc;
>> +	int ret;
>> +
>> +	ret = tee_client_close_session(tee_rproc_ctx->tee_ctx, trproc->session_id);
>> +	if (ret < 0)
>> +		dev_err(trproc->parent,	"tee_client_close_session failed, err: %x\n", ret);
>> +
>> +	list_del(&trproc->node);
>> +	rproc->tee_interface = NULL;
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(tee_rproc_unregister);
>> +
>> +static int tee_rproc_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
>> +{
>> +	/* Today we support only the OP-TEE, could be extend to other tees */
>> +	return (ver->impl_id == TEE_IMPL_ID_OPTEE);
>> +}
>> +
>> +static int tee_rproc_probe(struct device *dev)
>> +{
>> +	struct tee_context *tee_ctx;
>> +	int ret;
>> +
>> +	/* Open context with TEE driver */
>> +	tee_ctx = tee_client_open_context(NULL, tee_rproc_ctx_match, NULL, NULL);
>> +	if (IS_ERR(tee_ctx))
>> +		return PTR_ERR(tee_ctx);
>> +
>> +	tee_rproc_ctx = devm_kzalloc(dev, sizeof(*tee_ctx), GFP_KERNEL);
>> +	if (!tee_rproc_ctx) {
>> +		ret = -ENOMEM;
>> +		goto err;
>> +	}
>> +
>> +	tee_rproc_ctx->dev = dev;
>> +	tee_rproc_ctx->tee_ctx = tee_ctx;
>> +	INIT_LIST_HEAD(&tee_rproc_ctx->sessions);
>> +
>> +	return 0;
>> +err:
>> +	tee_client_close_context(tee_ctx);
>> +
>> +	return ret;
>> +}
>> +
>> +static int tee_rproc_remove(struct device *dev)
>> +{
>> +	struct tee_rproc *entry, *tmp;
>> +
>> +	list_for_each_entry_safe(entry, tmp, &tee_rproc_ctx->sessions, node) {
>> +		tee_client_close_session(tee_rproc_ctx->tee_ctx, entry->session_id);
>> +		list_del(&entry->node);
>> +		if (entry->rsc_table)
>> +			iounmap(entry->rsc_table);
>> +		kfree(entry);
>> +	}
>> +
>> +	tee_client_close_context(tee_rproc_ctx->tee_ctx);
>> +
>> +	return 0;
>> +}
>> +
>> +MODULE_DEVICE_TABLE(tee, stm32_tee_rproc_id_table);
>> +
>> +static struct tee_client_driver tee_rproc_fw_driver = {
>> +	.id_table	= stm32_tee_rproc_id_table,
>> +	.driver		= {
>> +		.name		= KBUILD_MODNAME,
>> +		.bus		= &tee_bus_type,
>> +		.probe		= tee_rproc_probe,
>> +		.remove		= tee_rproc_remove,
>> +	},
>> +};
>> +
>> +static int __init tee_rproc_fw_mod_init(void)
>> +{
>> +	return driver_register(&tee_rproc_fw_driver.driver);
>> +}
>> +
>> +static void __exit tee_rproc_fw_mod_exit(void)
>> +{
>> +	driver_unregister(&tee_rproc_fw_driver.driver);
>> +}
>> +
>> +module_init(tee_rproc_fw_mod_init);
>> +module_exit(tee_rproc_fw_mod_exit);
>> +
>> +MODULE_DESCRIPTION(" TEE remote processor control driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> index b4795698d8c2..8b678009e481 100644
>> --- a/include/linux/remoteproc.h
>> +++ b/include/linux/remoteproc.h
>> @@ -503,6 +503,8 @@ enum rproc_features {
>>  	RPROC_MAX_FEATURES,
>>  };
>>  
>> +struct tee_rproc;
>> +
>>  /**
>>   * struct rproc - represents a physical remote processor device
>>   * @node: list node of this rproc object
>> @@ -545,6 +547,7 @@ enum rproc_features {
>>   * @cdev: character device of the rproc
>>   * @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release
>>   * @features: indicate remoteproc features
>> + * @tee_interface: pointer to the remoteproc tee context
>>   */
>>  struct rproc {
>>  	struct list_head node;
>> @@ -586,6 +589,7 @@ struct rproc {
>>  	struct cdev cdev;
>>  	bool cdev_put_on_release;
>>  	DECLARE_BITMAP(features, RPROC_MAX_FEATURES);
>> +	struct tee_rproc *tee_interface;
>>  };
>>  
>>  /**
>> diff --git a/include/linux/tee_remoteproc.h b/include/linux/tee_remoteproc.h
>> new file mode 100644
>> index 000000000000..571e47190d02
>> --- /dev/null
>> +++ b/include/linux/tee_remoteproc.h
>> @@ -0,0 +1,112 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * Copyright(c) 2024 STMicroelectronics - All Rights Reserved
>> + */
>> +
>> +#ifndef TEE_REMOTEPROC_H
>> +#define TEE_REMOTEPROC_H
>> +
>> +#include <linux/tee_drv.h>
>> +#include <linux/firmware.h>
>> +#include <linux/remoteproc.h>
>> +
>> +struct rproc;
>> +
>> +/**
>> + * struct tee_rproc - TEE remoteproc structure
>> + * @node:		Reference in list
>> + * @rproc:		Remoteproc reference
>> + * @parent:		Parent device
>> + * @rproc_id:		Identifier of the target firmware
>> + * @session_id:		TEE session identifier
>> + * @rsc_table:		Resource table virtual address.
>> + */
>> +struct tee_rproc {
>> +	struct list_head node;
>> +	struct rproc *rproc;
>> +	struct device *parent;
>> +	u32 rproc_id;
>> +	u32 session_id;
>> +	struct resource_table *rsc_table;
>> +};
>> +
>> +#if IS_REACHABLE(CONFIG_TEE_REMOTEPROC)
>> +
>> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
>> +				     unsigned int rproc_id);
>> +int tee_rproc_unregister(struct tee_rproc *trproc);
>> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw);
>> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw);
>> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz);
>> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
>> +						       const struct firmware *fw);
>> +int tee_rproc_start(struct rproc *rproc);
>> +int tee_rproc_stop(struct rproc *rproc);
>> +
>> +#else
>> +
>> +static inline struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
>> +						   unsigned int rproc_id)
>> +{
>> +	return ERR_PTR(-ENODEV);
>> +}
>> +
>> +static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
>> +{
>> +	/* This shouldn't be possible */
>> +	WARN_ON(1);
>> +
>> +	return 0;
>> +}
>> +
>> +static inline int tee_rproc_unregister(struct tee_rproc *trproc)
>> +{
>> +	/* This shouldn't be possible */
>> +	WARN_ON(1);
>> +
>> +	return 0;
>> +}
>> +
>> +static inline int tee_rproc_load_fw(struct rproc *rproc,  const struct firmware *fw)
>> +{
>> +	/* This shouldn't be possible */
>> +	WARN_ON(1);
>> +
>> +	return 0;
>> +}
>> +
>> +static inline int tee_rproc_start(struct rproc *rproc)
>> +{
>> +	/* This shouldn't be possible */
>> +	WARN_ON(1);
>> +
>> +	return 0;
>> +}
>> +
>> +static inline int tee_rproc_stop(struct rproc *rproc)
>> +{
>> +	/* This shouldn't be possible */
>> +	WARN_ON(1);
>> +
>> +	return 0;
>> +}
>> +
>> +static inline struct resource_table *
>> +tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
>> +{
>> +	/* This shouldn't be possible */
>> +	WARN_ON(1);
>> +
>> +	return NULL;
>> +}
>> +
>> +static inline struct resource_table *
>> +tee_rproc_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
>> +{
>> +	/* This shouldn't be possible */
>> +	WARN_ON(1);
>> +
>> +	return NULL;
>> +}
>> +#endif /* CONFIG_TEE_REMOTEPROC */
>> +#endif /* TEE_REMOTEPROC_H */
>> -- 
>> 2.25.1
>>
Arnaud POULIQUEN March 26, 2024, 7:31 p.m. UTC | #5
On 3/25/24 17:51, Mathieu Poirier wrote:
> On Fri, Mar 08, 2024 at 03:47:08PM +0100, Arnaud Pouliquen wrote:
>> The new TEE remoteproc device is used to manage remote firmware in a
>> secure, trusted context. The 'st,stm32mp1-m4-tee' compatibility is
>> introduced to delegate the loading of the firmware to the trusted
>> execution context. In such cases, the firmware should be signed and
>> adhere to the image format defined by the TEE.
>>
>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>> ---
>> Updates from V3:
>> - remove support of the attach use case. Will be addressed in a separate
>>   thread,
>> - add st_rproc_tee_ops::parse_fw ops,
>> - inverse call of devm_rproc_alloc()and tee_rproc_register() to manage cross
>>   reference between the rproc struct and the tee_rproc struct in tee_rproc.c.
>> ---
>>  drivers/remoteproc/stm32_rproc.c | 60 +++++++++++++++++++++++++++++---
>>  1 file changed, 56 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
>> index 8cd838df4e92..13df33c78aa2 100644
>> --- a/drivers/remoteproc/stm32_rproc.c
>> +++ b/drivers/remoteproc/stm32_rproc.c
>> @@ -20,6 +20,7 @@
>>  #include <linux/remoteproc.h>
>>  #include <linux/reset.h>
>>  #include <linux/slab.h>
>> +#include <linux/tee_remoteproc.h>
>>  #include <linux/workqueue.h>
>>  
>>  #include "remoteproc_internal.h"
>> @@ -49,6 +50,9 @@
>>  #define M4_STATE_STANDBY	4
>>  #define M4_STATE_CRASH		5
>>  
>> +/* Remote processor unique identifier aligned with the Trusted Execution Environment definitions */
> 
> Why is this the case?  At least from the kernel side it is possible to call
> tee_rproc_register() with any kind of value, why is there a need to be any
> kind of alignment with the TEE?


The use of the proc_id is to identify a processor in case of multi co-processors.

For instance we can have a system with A DSP and a modem. We would use the same
TEE service, but
the TEE driver will probably be different, same for the signature key.
In such case the proc ID allows to identify the the processor you want to address.


> 
>> +#define STM32_MP1_M4_PROC_ID    0
>> +
>>  struct stm32_syscon {
>>  	struct regmap *map;
>>  	u32 reg;
>> @@ -257,6 +261,19 @@ static int stm32_rproc_release(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> +static int stm32_rproc_tee_stop(struct rproc *rproc)
>> +{
>> +	int err;
>> +
>> +	stm32_rproc_request_shutdown(rproc);
>> +
>> +	err = tee_rproc_stop(rproc);
>> +	if (err)
>> +		return err;
>> +
>> +	return stm32_rproc_release(rproc);
>> +}
>> +
>>  static int stm32_rproc_prepare(struct rproc *rproc)
>>  {
>>  	struct device *dev = rproc->dev.parent;
>> @@ -693,8 +710,19 @@ static const struct rproc_ops st_rproc_ops = {
>>  	.get_boot_addr	= rproc_elf_get_boot_addr,
>>  };
>>  
>> +static const struct rproc_ops st_rproc_tee_ops = {
>> +	.prepare	= stm32_rproc_prepare,
>> +	.start		= tee_rproc_start,
>> +	.stop		= stm32_rproc_tee_stop,
>> +	.kick		= stm32_rproc_kick,
>> +	.load		= tee_rproc_load_fw,
>> +	.parse_fw	= tee_rproc_parse_fw,
>> +	.find_loaded_rsc_table = tee_rproc_find_loaded_rsc_table,
>> +};
>> +
>>  static const struct of_device_id stm32_rproc_match[] = {
>> -	{ .compatible = "st,stm32mp1-m4" },
>> +	{.compatible = "st,stm32mp1-m4",},
>> +	{.compatible = "st,stm32mp1-m4-tee",},
>>  	{},
>>  };
>>  MODULE_DEVICE_TABLE(of, stm32_rproc_match);
>> @@ -853,6 +881,7 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>  	struct device *dev = &pdev->dev;
>>  	struct stm32_rproc *ddata;
>>  	struct device_node *np = dev->of_node;
>> +	struct tee_rproc *trproc = NULL;
>>  	struct rproc *rproc;
>>  	unsigned int state;
>>  	int ret;
>> @@ -861,9 +890,26 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>  	if (ret)
>>  		return ret;
>>  
>> -	rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
>> -	if (!rproc)
>> -		return -ENOMEM;
>> +	if (of_device_is_compatible(np, "st,stm32mp1-m4-tee")) {
>> +		/*
>> +		 * Delegate the firmware management to the secure context.
>> +		 * The firmware loaded has to be signed.
>> +		 */
>> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
>> +		if (!rproc)
>> +			return -ENOMEM;
>> +
>> +		trproc = tee_rproc_register(dev, rproc, STM32_MP1_M4_PROC_ID);
>> +		if (IS_ERR(trproc)) {
>> +			dev_err_probe(dev, PTR_ERR(trproc),
>> +				      "signed firmware not supported by TEE\n");
>> +			return PTR_ERR(trproc);
>> +		}
>> +	} else {
>> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
>> +		if (!rproc)
>> +			return -ENOMEM;
>> +	}
>>  
>>  	ddata = rproc->priv;
>>  
>> @@ -915,6 +961,9 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>  		dev_pm_clear_wake_irq(dev);
>>  		device_init_wakeup(dev, false);
>>  	}
>> +	if (trproc)
> 
>         if (rproc->tee_interface)
> 
> 
> I am done reviewing this set.

Thank for your review!
Arnaud

> 
> Thanks,
> Mathieu
> 
>> +		tee_rproc_unregister(trproc);
>> +
>>  	return ret;
>>  }
>>  
>> @@ -935,6 +984,9 @@ static void stm32_rproc_remove(struct platform_device *pdev)
>>  		dev_pm_clear_wake_irq(dev);
>>  		device_init_wakeup(dev, false);
>>  	}
>> +	if (rproc->tee_interface)
>> +		tee_rproc_unregister(rproc->tee_interface);
>> +
>>  }
>>  
>>  static int stm32_rproc_suspend(struct device *dev)
>> -- 
>> 2.25.1
>>
Mathieu Poirier March 27, 2024, 5:07 p.m. UTC | #6
On Tue, Mar 26, 2024 at 08:18:23PM +0100, Arnaud POULIQUEN wrote:
> Hello Mathieu,
> 
> On 3/25/24 17:46, Mathieu Poirier wrote:
> > On Fri, Mar 08, 2024 at 03:47:05PM +0100, Arnaud Pouliquen wrote:
> >> Add a remoteproc TEE (Trusted Execution Environment) driver
> >> that will be probed by the TEE bus. If the associated Trusted
> >> application is supported on secure part this device offers a client
> > 
> > Device or driver?  I thought I touched on that before.
> 
> Right, I changed the first instance and missed this one
> 
> > 
> >> interface to load a firmware in the secure part.
> >> This firmware could be authenticated by the secure trusted application.
> >>
> >> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> >> ---
> >> Updates from V3:
> >> - rework TEE_REMOTEPROC description in Kconfig
> >> - fix some namings
> >> - add tee_rproc_parse_fw  to support rproc_ops::parse_fw
> >> - add proc::tee_interface;
> >> - add rproc struct as parameter of the tee_rproc_register() function
> >> ---
> >>  drivers/remoteproc/Kconfig          |  10 +
> >>  drivers/remoteproc/Makefile         |   1 +
> >>  drivers/remoteproc/tee_remoteproc.c | 434 ++++++++++++++++++++++++++++
> >>  include/linux/remoteproc.h          |   4 +
> >>  include/linux/tee_remoteproc.h      | 112 +++++++
> >>  5 files changed, 561 insertions(+)
> >>  create mode 100644 drivers/remoteproc/tee_remoteproc.c
> >>  create mode 100644 include/linux/tee_remoteproc.h
> >>
> >> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> >> index 48845dc8fa85..2cf1431b2b59 100644
> >> --- a/drivers/remoteproc/Kconfig
> >> +++ b/drivers/remoteproc/Kconfig
> >> @@ -365,6 +365,16 @@ config XLNX_R5_REMOTEPROC
> >>  
> >>  	  It's safe to say N if not interested in using RPU r5f cores.
> >>  
> >> +
> >> +config TEE_REMOTEPROC
> >> +	tristate "remoteproc support by a TEE application"
> > 
> > s/remoteproc/Remoteproc
> > 
> >> +	depends on OPTEE
> >> +	help
> >> +	  Support a remote processor with a TEE application. The Trusted
> >> +	  Execution Context is responsible for loading the trusted firmware
> >> +	  image and managing the remote processor's lifecycle.
> >> +	  This can be either built-in or a loadable module.
> >> +
> >>  endif # REMOTEPROC
> >>  
> >>  endmenu
> >> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
> >> index 91314a9b43ce..fa8daebce277 100644
> >> --- a/drivers/remoteproc/Makefile
> >> +++ b/drivers/remoteproc/Makefile
> >> @@ -36,6 +36,7 @@ obj-$(CONFIG_RCAR_REMOTEPROC)		+= rcar_rproc.o
> >>  obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
> >>  obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
> >>  obj-$(CONFIG_STM32_RPROC)		+= stm32_rproc.o
> >> +obj-$(CONFIG_TEE_REMOTEPROC)		+= tee_remoteproc.o
> >>  obj-$(CONFIG_TI_K3_DSP_REMOTEPROC)	+= ti_k3_dsp_remoteproc.o
> >>  obj-$(CONFIG_TI_K3_R5_REMOTEPROC)	+= ti_k3_r5_remoteproc.o
> >>  obj-$(CONFIG_XLNX_R5_REMOTEPROC)	+= xlnx_r5_remoteproc.o
> >> diff --git a/drivers/remoteproc/tee_remoteproc.c b/drivers/remoteproc/tee_remoteproc.c
> >> new file mode 100644
> >> index 000000000000..c855210e52e3
> >> --- /dev/null
> >> +++ b/drivers/remoteproc/tee_remoteproc.c
> >> @@ -0,0 +1,434 @@
> >> +// SPDX-License-Identifier: GPL-2.0-or-later
> >> +/*
> >> + * Copyright (C) STMicroelectronics 2024 - All Rights Reserved
> >> + * Author: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> >> + */
> >> +
> >> +#include <linux/firmware.h>
> >> +#include <linux/io.h>
> >> +#include <linux/module.h>
> >> +#include <linux/remoteproc.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/tee_drv.h>
> >> +#include <linux/tee_remoteproc.h>
> >> +
> >> +#include "remoteproc_internal.h"
> >> +
> >> +#define MAX_TEE_PARAM_ARRY_MEMBER	4
> >> +
> >> +/*
> >> + * Authentication of the firmware and load in the remote processor memory
> >> + *
> >> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >> + * [in]	 params[1].memref:	buffer containing the image of the buffer
> >> + */
> >> +#define TA_RPROC_FW_CMD_LOAD_FW		1
> >> +
> >> +/*
> >> + * Start the remote processor
> >> + *
> >> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >> + */
> >> +#define TA_RPROC_FW_CMD_START_FW	2
> >> +
> >> +/*
> >> + * Stop the remote processor
> >> + *
> >> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >> + */
> >> +#define TA_RPROC_FW_CMD_STOP_FW		3
> >> +
> >> +/*
> >> + * Return the address of the resource table, or 0 if not found
> >> + * No check is done to verify that the address returned is accessible by
> >> + * the non secure context. If the resource table is loaded in a protected
> >> + * memory the access by the non secure context will lead to a data abort.
> >> + *
> >> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >> + * [out]  params[1].value.a:	32bit LSB resource table memory address
> >> + * [out]  params[1].value.b:	32bit MSB resource table memory address
> >> + * [out]  params[2].value.a:	32bit LSB resource table memory size
> >> + * [out]  params[2].value.b:	32bit MSB resource table memory size
> >> + */
> >> +#define TA_RPROC_FW_CMD_GET_RSC_TABLE	4
> >> +
> >> +/*
> >> + * Return the address of the core dump
> >> + *
> >> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >> + * [out] params[1].memref:	address of the core dump image if exist,
> >> + *				else return Null
> >> + */
> >> +#define TA_RPROC_FW_CMD_GET_COREDUMP	5
> >> +
> >> +struct tee_rproc_context {
> >> +	struct list_head sessions;
> >> +	struct tee_context *tee_ctx;
> >> +	struct device *dev;
> >> +};
> >> +
> >> +static struct tee_rproc_context *tee_rproc_ctx;
> >> +
> >> +static void tee_rproc_prepare_args(struct tee_rproc *trproc, int cmd,
> >> +				   struct tee_ioctl_invoke_arg *arg,
> >> +				   struct tee_param *param,
> >> +				   unsigned int num_params)
> >> +{
> >> +	memset(arg, 0, sizeof(*arg));
> >> +	memset(param, 0, MAX_TEE_PARAM_ARRY_MEMBER * sizeof(*param));
> >> +
> >> +	arg->func = cmd;
> >> +	arg->session = trproc->session_id;
> >> +	arg->num_params = num_params + 1;
> >> +
> >> +	param[0] = (struct tee_param) {
> >> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> >> +		.u.value.a = trproc->rproc_id,
> >> +	};
> >> +}
> >> +
> >> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
> >> +{
> >> +	struct tee_ioctl_invoke_arg arg;
> >> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >> +	struct tee_rproc *trproc = rproc->tee_interface;
> >> +	struct tee_shm *fw_shm;
> >> +	int ret;
> > 
> > Declarations in reverse ascending order here and everywhere in the driver.
> > Sometimes it is done properly, sometimes it isn't. 
> > 
> >> +
> >> +	if (!trproc)
> >> +		return -EINVAL;
> >> +
> >> +	fw_shm = tee_shm_register_kernel_buf(tee_rproc_ctx->tee_ctx, (void *)fw->data, fw->size);
> >> +	if (IS_ERR(fw_shm))
> >> +		return PTR_ERR(fw_shm);
> >> +
> >> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_LOAD_FW, &arg, param, 1);
> >> +
> >> +	/* Provide the address of the firmware image */
> >> +	param[1] = (struct tee_param) {
> >> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
> >> +		.u.memref = {
> >> +			.shm = fw_shm,
> >> +			.size = fw->size,
> >> +			.shm_offs = 0,
> >> +		},
> >> +	};
> >> +
> >> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> >> +	if (ret < 0 || arg.ret != 0) {
> >> +		dev_err(tee_rproc_ctx->dev,
> >> +			"TA_RPROC_FW_CMD_LOAD_FW invoke failed TEE err: %x, ret:%x\n",
> >> +			arg.ret, ret);
> >> +		if (!ret)
> >> +			ret = -EIO;
> >> +	}
> >> +
> >> +	tee_shm_free(fw_shm);
> >> +
> >> +	return ret;
> >> +}
> >> +EXPORT_SYMBOL_GPL(tee_rproc_load_fw);
> >> +
> >> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
> >> +{
> >> +	struct tee_ioctl_invoke_arg arg;
> >> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >> +	struct tee_rproc *trproc = rproc->tee_interface;
> >> +	struct resource_table *rsc_table;
> >> +	int ret;
> >> +
> >> +	if (!trproc)
> >> +		return ERR_PTR(-EINVAL);
> >> +
> >> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_GET_RSC_TABLE, &arg, param, 2);
> >> +
> >> +	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> >> +	param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> >> +
> >> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> >> +	if (ret < 0 || arg.ret != 0) {
> >> +		dev_err(tee_rproc_ctx->dev,
> >> +			"TA_RPROC_FW_CMD_GET_RSC_TABLE invoke failed TEE err: %x, ret:%x\n",
> >> +			arg.ret, ret);
> >> +		return ERR_PTR(-EIO);
> >> +	}
> >> +
> >> +	*table_sz = param[2].u.value.a;
> >> +
> >> +	/* If the size is null no resource table defined in the image */
> >> +	if (!*table_sz)
> >> +		return NULL;
> >> +
> >> +	/* Store the resource table address that would be updated by the remote core. */
> >> +	rsc_table = ioremap_wc(param[1].u.value.a, *table_sz);
> >> +	if (IS_ERR_OR_NULL(rsc_table)) {
> >> +		dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %lld+%zx\n",
> >> +			param[1].u.value.a, *table_sz);
> >> +		return ERR_PTR(-ENOMEM);
> >> +	}
> >> +
> >> +	return rsc_table;
> >> +}
> >> +EXPORT_SYMBOL_GPL(tee_rproc_get_loaded_rsc_table);
> >> +
> >> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> >> +{
> >> +	struct tee_rproc *trproc = rproc->tee_interface;
> >> +	struct resource_table *rsc_table;
> >> +	size_t table_sz;
> >> +	int ret;
> >> +
> >> +	ret = tee_rproc_load_fw(rproc, fw);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
> >> +	if (IS_ERR(rsc_table))
> >> +		return PTR_ERR(rsc_table);
> >> +
> >> +	/* Create a copy of the resource table to have same behaviour than the elf loader. */
> >> +	rproc->cached_table = kmemdup(rsc_table, table_sz, GFP_KERNEL);
> >> +	if (!rproc->cached_table)
> >> +		return -ENOMEM;
> > 
> > Why not ->table_ptr and setting ->cached_table to NULL?
> 
> It was my plan preparing this version. But during implementarion it looks
> to me that having exactly same behavior than the ELF loader would be
> simpler to maintain the remoteproc avoiding to update in the remoteproc core
> to manage for the cached resource table (see also my comment below abourt recovery)
> That why I propose this implementation
> 
> That said what you proposal should also work (with some updates in
> remoteproc_core for the management of the cached table).
>

Yes

> So please just comfirm your preference.
>

Definitely keep ->cached_table to NULL.  

> > 
> >> +
> >> +	rproc->table_ptr = rproc->cached_table;
> >> +	rproc->table_sz = table_sz;
> >> +	trproc->rsc_table = rsc_table;
> > 
> > I really don't see why this is needed, please remove and use rproc->table_ptr
> > instead.
> 
> I need to store it for the iounmap in tee_rproc_remove.

iounmap(entry->rproc->rsc_table);

What am I missing?

> 
> > 
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL_GPL(tee_rproc_parse_fw);
> >> +
> >> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
> >> +						       const struct firmware *fw)
> >> +{
> >> +	struct tee_rproc *trproc = rproc->tee_interface;
> >> +	struct resource_table *rsc_table;
> >> +	size_t table_sz;
> >> +
> >> +	if (!trproc)
> >> +		return ERR_PTR(-EINVAL);
> >> +
> >> +	/* Check if the resourse table has already been obtained in tee_rproc_parse_fw() */
> >> +	if (trproc->rsc_table)
> >> +		return trproc->rsc_table;
> > 
> > Again, why not simply use rproc->rsc_table?  This function should only return
> > the resource table that was set in tee_rproc_parse_fw(). 
> 
> In case of recovery rproc->_rsc_table point to the cached table [1]
 
In [1], on line 1554, add a check for rproc->tee_interface and if it is valid
call rproc_find_loaded_rsc_table(). 

> and we need to reapply the configuration in rproc_start() called during the
> recovery[2]

1) Rename rproc_set_rsc_table() to rproc_set_rsc_table_on_attach()
2) Introduce a new function called rproc_set_rsc_table_on_start()
3) Move code from [2], line 1278 to 1292, to that new function.  In the new
function, add a check on rproc->tee_interface.  If it is valid then call
rproc_find_loaded_rsc_table().
4) in rproc_start(), replace lines 1278 to 1292 with a call to
rproc_set_rsc_table_on_start().

> [1]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1586
> [2]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1287
> 
> > 
> >> +
> >> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
> >> +	if (IS_ERR(rsc_table))
> >> +		return rsc_table;
> >> +
> >> +	rproc->table_sz = table_sz;
> >> +	trproc->rsc_table = rsc_table;
> >> +
> >> +	return rsc_table;
> >> +}
> >> +EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
> >> +
> >> +int tee_rproc_start(struct rproc *rproc)
> >> +{
> >> +	struct tee_ioctl_invoke_arg arg;
> >> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >> +	struct tee_rproc *trproc = rproc->tee_interface;
> >> +	int ret;
> >> +
> >> +	if (!trproc)
> >> +		return -EINVAL;
> >> +
> >> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_START_FW, &arg, param, 0);
> >> +
> >> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> >> +	if (ret < 0 || arg.ret != 0) {
> >> +		dev_err(tee_rproc_ctx->dev,
> >> +			"TA_RPROC_FW_CMD_START_FW invoke failed TEE err: %x, ret:%x\n",
> >> +			arg.ret, ret);
> >> +		if (!ret)
> >> +			ret = -EIO;
> >> +	}
> >> +
> >> +	return ret;
> >> +}
> >> +EXPORT_SYMBOL_GPL(tee_rproc_start);
> >> +
> >> +int tee_rproc_stop(struct rproc *rproc)
> >> +{
> >> +	struct tee_ioctl_invoke_arg arg;
> >> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >> +	struct tee_rproc *trproc = rproc->tee_interface;
> >> +	int ret;
> >> +
> >> +	if (!trproc)
> >> +		return -EINVAL;
> >> +
> >> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_STOP_FW, &arg, param, 0);
> >> +
> >> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> >> +	if (ret < 0 || arg.ret != 0) {
> >> +		dev_err(tee_rproc_ctx->dev,
> >> +			"TA_RPROC_FW_CMD_STOP_FW invoke failed TEE err: %x, ret:%x\n",
> >> +			arg.ret, ret);
> >> +		if (!ret)
> >> +			ret = -EIO;
> >> +	}
> >> +
> >> +	if (!rproc->table_ptr)
> >> +		return ret;
> >> +
> >> +	iounmap(trproc->rsc_table);
> >> +	trproc->rsc_table = NULL;
> >> +	rproc->table_ptr = NULL;
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL_GPL(tee_rproc_stop);
> >> +
> >> +static const struct tee_client_device_id stm32_tee_rproc_id_table[] = {
> >> +	{UUID_INIT(0x80a4c275, 0x0a47, 0x4905,
> >> +		   0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
> >> +	{}
> >> +};
> >> +
> >> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, unsigned int rproc_id)
> >> +{
> >> +	struct tee_client_device *tee_device;
> >> +	struct tee_ioctl_open_session_arg sess_arg;
> >> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >> +	struct tee_rproc *trproc;
> >> +	int ret;
> >> +
> >> +	/*
> >> +	 * Test if the device has been probed by the TEE bus. In case of failure, we ignore the
> >> +	 * reason. The bus could be not yet probed or the service not available in the secure
> >> +	 * firmware.The assumption in such a case is that the TEE remoteproc is not probed.
> >> +	 */
> >> +	if (!tee_rproc_ctx)
> >> +		return ERR_PTR(-EPROBE_DEFER);
> >> +
> >> +	trproc =  devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
> >> +	if (!trproc)
> >> +		return ERR_PTR(-ENOMEM);
> >> +
> >> +	tee_device = to_tee_client_device(tee_rproc_ctx->dev);
> >> +	memset(&sess_arg, 0, sizeof(sess_arg));
> >> +
> >> +	memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> >> +
> >> +	sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
> >> +	sess_arg.num_params = 1;
> >> +
> >> +	param[0] = (struct tee_param) {
> >> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> >> +		.u.value.a = rproc_id,
> >> +	};
> >> +
> >> +	ret = tee_client_open_session(tee_rproc_ctx->tee_ctx, &sess_arg, param);
> >> +	if (ret < 0 || sess_arg.ret != 0) {
> >> +		dev_err(dev, "tee_client_open_session failed, err: %x\n", sess_arg.ret);
> >> +		return ERR_PTR(-EINVAL);
> >> +	}
> >> +
> >> +	trproc->parent =  dev;
> >> +	trproc->rproc_id = rproc_id;
> >> +	trproc->session_id = sess_arg.session;
> >> +
> >> +	trproc->rproc = rproc;
> >> +	rproc->tee_interface = trproc;
> >> +
> >> +	list_add_tail(&trproc->node, &tee_rproc_ctx->sessions);
> >> +
> >> +	return trproc;
> > 
> > Once this function was called by a client, what prevents a user from unloading
> > the tee_remoteproc module and breaking everything?
> 
> Good point! seems better toremove the module build capability
> 

I was thinking more along the lines of try_module_get() and module_put() to
avoid bloating the core.

> Thanks,
> Arnaud
> 
> > 
> >> +}
> >> +EXPORT_SYMBOL_GPL(tee_rproc_register);
> >> +
> >> +int tee_rproc_unregister(struct tee_rproc *trproc)
> >> +{
> > 
> > If you pass a struct_rproc instead of a struct tee_rproc there is no need for
> > tee_rproc::rproc, which is only ever used in this function.
> > 
> > 
> >> +	struct rproc *rproc = trproc->rproc;
> >> +	int ret;
> >> +
> >> +	ret = tee_client_close_session(tee_rproc_ctx->tee_ctx, trproc->session_id);
> >> +	if (ret < 0)
> >> +		dev_err(trproc->parent,	"tee_client_close_session failed, err: %x\n", ret);
> >> +
> >> +	list_del(&trproc->node);
> >> +	rproc->tee_interface = NULL;
> >> +
> >> +	return ret;
> >> +}
> >> +EXPORT_SYMBOL_GPL(tee_rproc_unregister);
> >> +
> >> +static int tee_rproc_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> >> +{
> >> +	/* Today we support only the OP-TEE, could be extend to other tees */
> >> +	return (ver->impl_id == TEE_IMPL_ID_OPTEE);
> >> +}
> >> +
> >> +static int tee_rproc_probe(struct device *dev)
> >> +{
> >> +	struct tee_context *tee_ctx;
> >> +	int ret;
> >> +
> >> +	/* Open context with TEE driver */
> >> +	tee_ctx = tee_client_open_context(NULL, tee_rproc_ctx_match, NULL, NULL);
> >> +	if (IS_ERR(tee_ctx))
> >> +		return PTR_ERR(tee_ctx);
> >> +
> >> +	tee_rproc_ctx = devm_kzalloc(dev, sizeof(*tee_ctx), GFP_KERNEL);
> >> +	if (!tee_rproc_ctx) {
> >> +		ret = -ENOMEM;
> >> +		goto err;
> >> +	}
> >> +
> >> +	tee_rproc_ctx->dev = dev;
> >> +	tee_rproc_ctx->tee_ctx = tee_ctx;
> >> +	INIT_LIST_HEAD(&tee_rproc_ctx->sessions);
> >> +
> >> +	return 0;
> >> +err:
> >> +	tee_client_close_context(tee_ctx);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int tee_rproc_remove(struct device *dev)
> >> +{
> >> +	struct tee_rproc *entry, *tmp;
> >> +
> >> +	list_for_each_entry_safe(entry, tmp, &tee_rproc_ctx->sessions, node) {
> >> +		tee_client_close_session(tee_rproc_ctx->tee_ctx, entry->session_id);
> >> +		list_del(&entry->node);
> >> +		if (entry->rsc_table)
> >> +			iounmap(entry->rsc_table);
> >> +		kfree(entry);
> >> +	}
> >> +
> >> +	tee_client_close_context(tee_rproc_ctx->tee_ctx);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +MODULE_DEVICE_TABLE(tee, stm32_tee_rproc_id_table);
> >> +
> >> +static struct tee_client_driver tee_rproc_fw_driver = {
> >> +	.id_table	= stm32_tee_rproc_id_table,
> >> +	.driver		= {
> >> +		.name		= KBUILD_MODNAME,
> >> +		.bus		= &tee_bus_type,
> >> +		.probe		= tee_rproc_probe,
> >> +		.remove		= tee_rproc_remove,
> >> +	},
> >> +};
> >> +
> >> +static int __init tee_rproc_fw_mod_init(void)
> >> +{
> >> +	return driver_register(&tee_rproc_fw_driver.driver);
> >> +}
> >> +
> >> +static void __exit tee_rproc_fw_mod_exit(void)
> >> +{
> >> +	driver_unregister(&tee_rproc_fw_driver.driver);
> >> +}
> >> +
> >> +module_init(tee_rproc_fw_mod_init);
> >> +module_exit(tee_rproc_fw_mod_exit);
> >> +
> >> +MODULE_DESCRIPTION(" TEE remote processor control driver");
> >> +MODULE_LICENSE("GPL");
> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >> index b4795698d8c2..8b678009e481 100644
> >> --- a/include/linux/remoteproc.h
> >> +++ b/include/linux/remoteproc.h
> >> @@ -503,6 +503,8 @@ enum rproc_features {
> >>  	RPROC_MAX_FEATURES,
> >>  };
> >>  
> >> +struct tee_rproc;
> >> +
> >>  /**
> >>   * struct rproc - represents a physical remote processor device
> >>   * @node: list node of this rproc object
> >> @@ -545,6 +547,7 @@ enum rproc_features {
> >>   * @cdev: character device of the rproc
> >>   * @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release
> >>   * @features: indicate remoteproc features
> >> + * @tee_interface: pointer to the remoteproc tee context
> >>   */
> >>  struct rproc {
> >>  	struct list_head node;
> >> @@ -586,6 +589,7 @@ struct rproc {
> >>  	struct cdev cdev;
> >>  	bool cdev_put_on_release;
> >>  	DECLARE_BITMAP(features, RPROC_MAX_FEATURES);
> >> +	struct tee_rproc *tee_interface;
> >>  };
> >>  
> >>  /**
> >> diff --git a/include/linux/tee_remoteproc.h b/include/linux/tee_remoteproc.h
> >> new file mode 100644
> >> index 000000000000..571e47190d02
> >> --- /dev/null
> >> +++ b/include/linux/tee_remoteproc.h
> >> @@ -0,0 +1,112 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> >> +/*
> >> + * Copyright(c) 2024 STMicroelectronics - All Rights Reserved
> >> + */
> >> +
> >> +#ifndef TEE_REMOTEPROC_H
> >> +#define TEE_REMOTEPROC_H
> >> +
> >> +#include <linux/tee_drv.h>
> >> +#include <linux/firmware.h>
> >> +#include <linux/remoteproc.h>
> >> +
> >> +struct rproc;
> >> +
> >> +/**
> >> + * struct tee_rproc - TEE remoteproc structure
> >> + * @node:		Reference in list
> >> + * @rproc:		Remoteproc reference
> >> + * @parent:		Parent device
> >> + * @rproc_id:		Identifier of the target firmware
> >> + * @session_id:		TEE session identifier
> >> + * @rsc_table:		Resource table virtual address.
> >> + */
> >> +struct tee_rproc {
> >> +	struct list_head node;
> >> +	struct rproc *rproc;
> >> +	struct device *parent;
> >> +	u32 rproc_id;
> >> +	u32 session_id;
> >> +	struct resource_table *rsc_table;
> >> +};
> >> +
> >> +#if IS_REACHABLE(CONFIG_TEE_REMOTEPROC)
> >> +
> >> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
> >> +				     unsigned int rproc_id);
> >> +int tee_rproc_unregister(struct tee_rproc *trproc);
> >> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw);
> >> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw);
> >> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz);
> >> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
> >> +						       const struct firmware *fw);
> >> +int tee_rproc_start(struct rproc *rproc);
> >> +int tee_rproc_stop(struct rproc *rproc);
> >> +
> >> +#else
> >> +
> >> +static inline struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
> >> +						   unsigned int rproc_id)
> >> +{
> >> +	return ERR_PTR(-ENODEV);
> >> +}
> >> +
> >> +static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> >> +{
> >> +	/* This shouldn't be possible */
> >> +	WARN_ON(1);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static inline int tee_rproc_unregister(struct tee_rproc *trproc)
> >> +{
> >> +	/* This shouldn't be possible */
> >> +	WARN_ON(1);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static inline int tee_rproc_load_fw(struct rproc *rproc,  const struct firmware *fw)
> >> +{
> >> +	/* This shouldn't be possible */
> >> +	WARN_ON(1);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static inline int tee_rproc_start(struct rproc *rproc)
> >> +{
> >> +	/* This shouldn't be possible */
> >> +	WARN_ON(1);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static inline int tee_rproc_stop(struct rproc *rproc)
> >> +{
> >> +	/* This shouldn't be possible */
> >> +	WARN_ON(1);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static inline struct resource_table *
> >> +tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
> >> +{
> >> +	/* This shouldn't be possible */
> >> +	WARN_ON(1);
> >> +
> >> +	return NULL;
> >> +}
> >> +
> >> +static inline struct resource_table *
> >> +tee_rproc_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
> >> +{
> >> +	/* This shouldn't be possible */
> >> +	WARN_ON(1);
> >> +
> >> +	return NULL;
> >> +}
> >> +#endif /* CONFIG_TEE_REMOTEPROC */
> >> +#endif /* TEE_REMOTEPROC_H */
> >> -- 
> >> 2.25.1
> >>
Mathieu Poirier March 27, 2024, 5:14 p.m. UTC | #7
On Tue, Mar 26, 2024 at 08:31:33PM +0100, Arnaud POULIQUEN wrote:
> 
> 
> On 3/25/24 17:51, Mathieu Poirier wrote:
> > On Fri, Mar 08, 2024 at 03:47:08PM +0100, Arnaud Pouliquen wrote:
> >> The new TEE remoteproc device is used to manage remote firmware in a
> >> secure, trusted context. The 'st,stm32mp1-m4-tee' compatibility is
> >> introduced to delegate the loading of the firmware to the trusted
> >> execution context. In such cases, the firmware should be signed and
> >> adhere to the image format defined by the TEE.
> >>
> >> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> >> ---
> >> Updates from V3:
> >> - remove support of the attach use case. Will be addressed in a separate
> >>   thread,
> >> - add st_rproc_tee_ops::parse_fw ops,
> >> - inverse call of devm_rproc_alloc()and tee_rproc_register() to manage cross
> >>   reference between the rproc struct and the tee_rproc struct in tee_rproc.c.
> >> ---
> >>  drivers/remoteproc/stm32_rproc.c | 60 +++++++++++++++++++++++++++++---
> >>  1 file changed, 56 insertions(+), 4 deletions(-)
> >>
> >> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
> >> index 8cd838df4e92..13df33c78aa2 100644
> >> --- a/drivers/remoteproc/stm32_rproc.c
> >> +++ b/drivers/remoteproc/stm32_rproc.c
> >> @@ -20,6 +20,7 @@
> >>  #include <linux/remoteproc.h>
> >>  #include <linux/reset.h>
> >>  #include <linux/slab.h>
> >> +#include <linux/tee_remoteproc.h>
> >>  #include <linux/workqueue.h>
> >>  
> >>  #include "remoteproc_internal.h"
> >> @@ -49,6 +50,9 @@
> >>  #define M4_STATE_STANDBY	4
> >>  #define M4_STATE_CRASH		5
> >>  
> >> +/* Remote processor unique identifier aligned with the Trusted Execution Environment definitions */
> > 
> > Why is this the case?  At least from the kernel side it is possible to call
> > tee_rproc_register() with any kind of value, why is there a need to be any
> > kind of alignment with the TEE?
> 
> 
> The use of the proc_id is to identify a processor in case of multi co-processors.
>

That is well understood.

> For instance we can have a system with A DSP and a modem. We would use the same
> TEE service, but

That too.

> the TEE driver will probably be different, same for the signature key.

What TEE driver are we talking about here?

> In such case the proc ID allows to identify the the processor you want to address.
> 

That too is well understood, but there is no alignment needed with the TEE, i.e
the TEE application is not expecting a value of '0'.  We could set
STM32_MP1_M4_PROC_ID to 0xDEADBEEF and things would work.  This driver won't go
anywhere for as long as it is not the case.

> 
> > 
> >> +#define STM32_MP1_M4_PROC_ID    0
> >> +
> >>  struct stm32_syscon {
> >>  	struct regmap *map;
> >>  	u32 reg;
> >> @@ -257,6 +261,19 @@ static int stm32_rproc_release(struct rproc *rproc)
> >>  	return 0;
> >>  }
> >>  
> >> +static int stm32_rproc_tee_stop(struct rproc *rproc)
> >> +{
> >> +	int err;
> >> +
> >> +	stm32_rproc_request_shutdown(rproc);
> >> +
> >> +	err = tee_rproc_stop(rproc);
> >> +	if (err)
> >> +		return err;
> >> +
> >> +	return stm32_rproc_release(rproc);
> >> +}
> >> +
> >>  static int stm32_rproc_prepare(struct rproc *rproc)
> >>  {
> >>  	struct device *dev = rproc->dev.parent;
> >> @@ -693,8 +710,19 @@ static const struct rproc_ops st_rproc_ops = {
> >>  	.get_boot_addr	= rproc_elf_get_boot_addr,
> >>  };
> >>  
> >> +static const struct rproc_ops st_rproc_tee_ops = {
> >> +	.prepare	= stm32_rproc_prepare,
> >> +	.start		= tee_rproc_start,
> >> +	.stop		= stm32_rproc_tee_stop,
> >> +	.kick		= stm32_rproc_kick,
> >> +	.load		= tee_rproc_load_fw,
> >> +	.parse_fw	= tee_rproc_parse_fw,
> >> +	.find_loaded_rsc_table = tee_rproc_find_loaded_rsc_table,
> >> +};
> >> +
> >>  static const struct of_device_id stm32_rproc_match[] = {
> >> -	{ .compatible = "st,stm32mp1-m4" },
> >> +	{.compatible = "st,stm32mp1-m4",},
> >> +	{.compatible = "st,stm32mp1-m4-tee",},
> >>  	{},
> >>  };
> >>  MODULE_DEVICE_TABLE(of, stm32_rproc_match);
> >> @@ -853,6 +881,7 @@ static int stm32_rproc_probe(struct platform_device *pdev)
> >>  	struct device *dev = &pdev->dev;
> >>  	struct stm32_rproc *ddata;
> >>  	struct device_node *np = dev->of_node;
> >> +	struct tee_rproc *trproc = NULL;
> >>  	struct rproc *rproc;
> >>  	unsigned int state;
> >>  	int ret;
> >> @@ -861,9 +890,26 @@ static int stm32_rproc_probe(struct platform_device *pdev)
> >>  	if (ret)
> >>  		return ret;
> >>  
> >> -	rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
> >> -	if (!rproc)
> >> -		return -ENOMEM;
> >> +	if (of_device_is_compatible(np, "st,stm32mp1-m4-tee")) {
> >> +		/*
> >> +		 * Delegate the firmware management to the secure context.
> >> +		 * The firmware loaded has to be signed.
> >> +		 */
> >> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
> >> +		if (!rproc)
> >> +			return -ENOMEM;
> >> +
> >> +		trproc = tee_rproc_register(dev, rproc, STM32_MP1_M4_PROC_ID);
> >> +		if (IS_ERR(trproc)) {
> >> +			dev_err_probe(dev, PTR_ERR(trproc),
> >> +				      "signed firmware not supported by TEE\n");
> >> +			return PTR_ERR(trproc);
> >> +		}
> >> +	} else {
> >> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
> >> +		if (!rproc)
> >> +			return -ENOMEM;
> >> +	}
> >>  
> >>  	ddata = rproc->priv;
> >>  
> >> @@ -915,6 +961,9 @@ static int stm32_rproc_probe(struct platform_device *pdev)
> >>  		dev_pm_clear_wake_irq(dev);
> >>  		device_init_wakeup(dev, false);
> >>  	}
> >> +	if (trproc)
> > 
> >         if (rproc->tee_interface)
> > 
> > 
> > I am done reviewing this set.
> 
> Thank for your review!
> Arnaud
> 
> > 
> > Thanks,
> > Mathieu
> > 
> >> +		tee_rproc_unregister(trproc);
> >> +
> >>  	return ret;
> >>  }
> >>  
> >> @@ -935,6 +984,9 @@ static void stm32_rproc_remove(struct platform_device *pdev)
> >>  		dev_pm_clear_wake_irq(dev);
> >>  		device_init_wakeup(dev, false);
> >>  	}
> >> +	if (rproc->tee_interface)
> >> +		tee_rproc_unregister(rproc->tee_interface);
> >> +
> >>  }
> >>  
> >>  static int stm32_rproc_suspend(struct device *dev)
> >> -- 
> >> 2.25.1
> >>
Arnaud POULIQUEN March 29, 2024, 8:58 a.m. UTC | #8
Hello Mathieu,

On 3/27/24 18:07, Mathieu Poirier wrote:
> On Tue, Mar 26, 2024 at 08:18:23PM +0100, Arnaud POULIQUEN wrote:
>> Hello Mathieu,
>>
>> On 3/25/24 17:46, Mathieu Poirier wrote:
>>> On Fri, Mar 08, 2024 at 03:47:05PM +0100, Arnaud Pouliquen wrote:
>>>> Add a remoteproc TEE (Trusted Execution Environment) driver
>>>> that will be probed by the TEE bus. If the associated Trusted
>>>> application is supported on secure part this device offers a client
>>>
>>> Device or driver?  I thought I touched on that before.
>>
>> Right, I changed the first instance and missed this one
>>
>>>
>>>> interface to load a firmware in the secure part.
>>>> This firmware could be authenticated by the secure trusted application.
>>>>
>>>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>>>> ---
>>>> Updates from V3:
>>>> - rework TEE_REMOTEPROC description in Kconfig
>>>> - fix some namings
>>>> - add tee_rproc_parse_fw  to support rproc_ops::parse_fw
>>>> - add proc::tee_interface;
>>>> - add rproc struct as parameter of the tee_rproc_register() function
>>>> ---
>>>>  drivers/remoteproc/Kconfig          |  10 +
>>>>  drivers/remoteproc/Makefile         |   1 +
>>>>  drivers/remoteproc/tee_remoteproc.c | 434 ++++++++++++++++++++++++++++
>>>>  include/linux/remoteproc.h          |   4 +
>>>>  include/linux/tee_remoteproc.h      | 112 +++++++
>>>>  5 files changed, 561 insertions(+)
>>>>  create mode 100644 drivers/remoteproc/tee_remoteproc.c
>>>>  create mode 100644 include/linux/tee_remoteproc.h
>>>>
>>>> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
>>>> index 48845dc8fa85..2cf1431b2b59 100644
>>>> --- a/drivers/remoteproc/Kconfig
>>>> +++ b/drivers/remoteproc/Kconfig
>>>> @@ -365,6 +365,16 @@ config XLNX_R5_REMOTEPROC
>>>>  
>>>>  	  It's safe to say N if not interested in using RPU r5f cores.
>>>>  
>>>> +
>>>> +config TEE_REMOTEPROC
>>>> +	tristate "remoteproc support by a TEE application"
>>>
>>> s/remoteproc/Remoteproc
>>>
>>>> +	depends on OPTEE
>>>> +	help
>>>> +	  Support a remote processor with a TEE application. The Trusted
>>>> +	  Execution Context is responsible for loading the trusted firmware
>>>> +	  image and managing the remote processor's lifecycle.
>>>> +	  This can be either built-in or a loadable module.
>>>> +
>>>>  endif # REMOTEPROC
>>>>  
>>>>  endmenu
>>>> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
>>>> index 91314a9b43ce..fa8daebce277 100644
>>>> --- a/drivers/remoteproc/Makefile
>>>> +++ b/drivers/remoteproc/Makefile
>>>> @@ -36,6 +36,7 @@ obj-$(CONFIG_RCAR_REMOTEPROC)		+= rcar_rproc.o
>>>>  obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
>>>>  obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
>>>>  obj-$(CONFIG_STM32_RPROC)		+= stm32_rproc.o
>>>> +obj-$(CONFIG_TEE_REMOTEPROC)		+= tee_remoteproc.o
>>>>  obj-$(CONFIG_TI_K3_DSP_REMOTEPROC)	+= ti_k3_dsp_remoteproc.o
>>>>  obj-$(CONFIG_TI_K3_R5_REMOTEPROC)	+= ti_k3_r5_remoteproc.o
>>>>  obj-$(CONFIG_XLNX_R5_REMOTEPROC)	+= xlnx_r5_remoteproc.o
>>>> diff --git a/drivers/remoteproc/tee_remoteproc.c b/drivers/remoteproc/tee_remoteproc.c
>>>> new file mode 100644
>>>> index 000000000000..c855210e52e3
>>>> --- /dev/null
>>>> +++ b/drivers/remoteproc/tee_remoteproc.c
>>>> @@ -0,0 +1,434 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-or-later
>>>> +/*
>>>> + * Copyright (C) STMicroelectronics 2024 - All Rights Reserved
>>>> + * Author: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>>>> + */
>>>> +
>>>> +#include <linux/firmware.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/remoteproc.h>
>>>> +#include <linux/slab.h>
>>>> +#include <linux/tee_drv.h>
>>>> +#include <linux/tee_remoteproc.h>
>>>> +
>>>> +#include "remoteproc_internal.h"
>>>> +
>>>> +#define MAX_TEE_PARAM_ARRY_MEMBER	4
>>>> +
>>>> +/*
>>>> + * Authentication of the firmware and load in the remote processor memory
>>>> + *
>>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>>>> + * [in]	 params[1].memref:	buffer containing the image of the buffer
>>>> + */
>>>> +#define TA_RPROC_FW_CMD_LOAD_FW		1
>>>> +
>>>> +/*
>>>> + * Start the remote processor
>>>> + *
>>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>>>> + */
>>>> +#define TA_RPROC_FW_CMD_START_FW	2
>>>> +
>>>> +/*
>>>> + * Stop the remote processor
>>>> + *
>>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>>>> + */
>>>> +#define TA_RPROC_FW_CMD_STOP_FW		3
>>>> +
>>>> +/*
>>>> + * Return the address of the resource table, or 0 if not found
>>>> + * No check is done to verify that the address returned is accessible by
>>>> + * the non secure context. If the resource table is loaded in a protected
>>>> + * memory the access by the non secure context will lead to a data abort.
>>>> + *
>>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>>>> + * [out]  params[1].value.a:	32bit LSB resource table memory address
>>>> + * [out]  params[1].value.b:	32bit MSB resource table memory address
>>>> + * [out]  params[2].value.a:	32bit LSB resource table memory size
>>>> + * [out]  params[2].value.b:	32bit MSB resource table memory size
>>>> + */
>>>> +#define TA_RPROC_FW_CMD_GET_RSC_TABLE	4
>>>> +
>>>> +/*
>>>> + * Return the address of the core dump
>>>> + *
>>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
>>>> + * [out] params[1].memref:	address of the core dump image if exist,
>>>> + *				else return Null
>>>> + */
>>>> +#define TA_RPROC_FW_CMD_GET_COREDUMP	5
>>>> +
>>>> +struct tee_rproc_context {
>>>> +	struct list_head sessions;
>>>> +	struct tee_context *tee_ctx;
>>>> +	struct device *dev;
>>>> +};
>>>> +
>>>> +static struct tee_rproc_context *tee_rproc_ctx;
>>>> +
>>>> +static void tee_rproc_prepare_args(struct tee_rproc *trproc, int cmd,
>>>> +				   struct tee_ioctl_invoke_arg *arg,
>>>> +				   struct tee_param *param,
>>>> +				   unsigned int num_params)
>>>> +{
>>>> +	memset(arg, 0, sizeof(*arg));
>>>> +	memset(param, 0, MAX_TEE_PARAM_ARRY_MEMBER * sizeof(*param));
>>>> +
>>>> +	arg->func = cmd;
>>>> +	arg->session = trproc->session_id;
>>>> +	arg->num_params = num_params + 1;
>>>> +
>>>> +	param[0] = (struct tee_param) {
>>>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
>>>> +		.u.value.a = trproc->rproc_id,
>>>> +	};
>>>> +}
>>>> +
>>>> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
>>>> +{
>>>> +	struct tee_ioctl_invoke_arg arg;
>>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>>>> +	struct tee_rproc *trproc = rproc->tee_interface;
>>>> +	struct tee_shm *fw_shm;
>>>> +	int ret;
>>>
>>> Declarations in reverse ascending order here and everywhere in the driver.
>>> Sometimes it is done properly, sometimes it isn't. 
>>>
>>>> +
>>>> +	if (!trproc)
>>>> +		return -EINVAL;
>>>> +
>>>> +	fw_shm = tee_shm_register_kernel_buf(tee_rproc_ctx->tee_ctx, (void *)fw->data, fw->size);
>>>> +	if (IS_ERR(fw_shm))
>>>> +		return PTR_ERR(fw_shm);
>>>> +
>>>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_LOAD_FW, &arg, param, 1);
>>>> +
>>>> +	/* Provide the address of the firmware image */
>>>> +	param[1] = (struct tee_param) {
>>>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
>>>> +		.u.memref = {
>>>> +			.shm = fw_shm,
>>>> +			.size = fw->size,
>>>> +			.shm_offs = 0,
>>>> +		},
>>>> +	};
>>>> +
>>>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
>>>> +	if (ret < 0 || arg.ret != 0) {
>>>> +		dev_err(tee_rproc_ctx->dev,
>>>> +			"TA_RPROC_FW_CMD_LOAD_FW invoke failed TEE err: %x, ret:%x\n",
>>>> +			arg.ret, ret);
>>>> +		if (!ret)
>>>> +			ret = -EIO;
>>>> +	}
>>>> +
>>>> +	tee_shm_free(fw_shm);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tee_rproc_load_fw);
>>>> +
>>>> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
>>>> +{
>>>> +	struct tee_ioctl_invoke_arg arg;
>>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>>>> +	struct tee_rproc *trproc = rproc->tee_interface;
>>>> +	struct resource_table *rsc_table;
>>>> +	int ret;
>>>> +
>>>> +	if (!trproc)
>>>> +		return ERR_PTR(-EINVAL);
>>>> +
>>>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_GET_RSC_TABLE, &arg, param, 2);
>>>> +
>>>> +	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
>>>> +	param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
>>>> +
>>>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
>>>> +	if (ret < 0 || arg.ret != 0) {
>>>> +		dev_err(tee_rproc_ctx->dev,
>>>> +			"TA_RPROC_FW_CMD_GET_RSC_TABLE invoke failed TEE err: %x, ret:%x\n",
>>>> +			arg.ret, ret);
>>>> +		return ERR_PTR(-EIO);
>>>> +	}
>>>> +
>>>> +	*table_sz = param[2].u.value.a;
>>>> +
>>>> +	/* If the size is null no resource table defined in the image */
>>>> +	if (!*table_sz)
>>>> +		return NULL;
>>>> +
>>>> +	/* Store the resource table address that would be updated by the remote core. */
>>>> +	rsc_table = ioremap_wc(param[1].u.value.a, *table_sz);
>>>> +	if (IS_ERR_OR_NULL(rsc_table)) {
>>>> +		dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %lld+%zx\n",
>>>> +			param[1].u.value.a, *table_sz);
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +	}
>>>> +
>>>> +	return rsc_table;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tee_rproc_get_loaded_rsc_table);
>>>> +
>>>> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
>>>> +{
>>>> +	struct tee_rproc *trproc = rproc->tee_interface;
>>>> +	struct resource_table *rsc_table;
>>>> +	size_t table_sz;
>>>> +	int ret;
>>>> +
>>>> +	ret = tee_rproc_load_fw(rproc, fw);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
>>>> +	if (IS_ERR(rsc_table))
>>>> +		return PTR_ERR(rsc_table);
>>>> +
>>>> +	/* Create a copy of the resource table to have same behaviour than the elf loader. */
>>>> +	rproc->cached_table = kmemdup(rsc_table, table_sz, GFP_KERNEL);
>>>> +	if (!rproc->cached_table)
>>>> +		return -ENOMEM;
>>>
>>> Why not ->table_ptr and setting ->cached_table to NULL?
>>
>> It was my plan preparing this version. But during implementarion it looks
>> to me that having exactly same behavior than the ELF loader would be
>> simpler to maintain the remoteproc avoiding to update in the remoteproc core
>> to manage for the cached resource table (see also my comment below abourt recovery)
>> That why I propose this implementation
>>
>> That said what you proposal should also work (with some updates in
>> remoteproc_core for the management of the cached table).
>>
> 
> Yes
> 
>> So please just comfirm your preference.
>>
> 
> Definitely keep ->cached_table to NULL.  
> 
>>>
>>>> +
>>>> +	rproc->table_ptr = rproc->cached_table;
>>>> +	rproc->table_sz = table_sz;
>>>> +	trproc->rsc_table = rsc_table;
>>>
>>> I really don't see why this is needed, please remove and use rproc->table_ptr
>>> instead.
>>
>> I need to store it for the iounmap in tee_rproc_remove.
> 
> iounmap(entry->rproc->rsc_table);
> 
> What am I missing?

rproc->rsc_table is a field that can be updated by remoteproc_core.
How can we garanty in tee_remoteproc that it still points to the mapped resource
table?
As the remoteproc_tee maps the pointer, it seems reliable that it stores it for
unmap.

Seems also that I also missed to  handle the case where rproc_fw_boot() fails[3]
(not done yet).

[3]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1442


> 
>>
>>>
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tee_rproc_parse_fw);
>>>> +
>>>> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
>>>> +						       const struct firmware *fw)
>>>> +{
>>>> +	struct tee_rproc *trproc = rproc->tee_interface;
>>>> +	struct resource_table *rsc_table;
>>>> +	size_t table_sz;
>>>> +
>>>> +	if (!trproc)
>>>> +		return ERR_PTR(-EINVAL);
>>>> +
>>>> +	/* Check if the resourse table has already been obtained in tee_rproc_parse_fw() */
>>>> +	if (trproc->rsc_table)
>>>> +		return trproc->rsc_table;
>>>
>>> Again, why not simply use rproc->rsc_table?  This function should only return
>>> the resource table that was set in tee_rproc_parse_fw(). 
>>
>> In case of recovery rproc->_rsc_table point to the cached table [1]
>  
> In [1], on line 1554, add a check for rproc->tee_interface and if it is valid
> call rproc_find_loaded_rsc_table(). 
> 
>> and we need to reapply the configuration in rproc_start() called during the
>> recovery[2]
> 
> 1) Rename rproc_set_rsc_table() to rproc_set_rsc_table_on_attach()
> 2) Introduce a new function called rproc_set_rsc_table_on_start()
> 3) Move code from [2], line 1278 to 1292, to that new function.  In the new
> function, add a check on rproc->tee_interface.  If it is valid then call
> rproc_find_loaded_rsc_table().
> 4) in rproc_start(), replace lines 1278 to 1292 with a call to
> rproc_set_rsc_table_on_start().


I will try this

Thanks!
Arnaud

> 
>> [1]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1586
>> [2]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1287
>>
>>>
>>>> +
>>>> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
>>>> +	if (IS_ERR(rsc_table))
>>>> +		return rsc_table;
>>>> +
>>>> +	rproc->table_sz = table_sz;
>>>> +	trproc->rsc_table = rsc_table;
>>>> +
>>>> +	return rsc_table;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
>>>> +
>>>> +int tee_rproc_start(struct rproc *rproc)
>>>> +{
>>>> +	struct tee_ioctl_invoke_arg arg;
>>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>>>> +	struct tee_rproc *trproc = rproc->tee_interface;
>>>> +	int ret;
>>>> +
>>>> +	if (!trproc)
>>>> +		return -EINVAL;
>>>> +
>>>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_START_FW, &arg, param, 0);
>>>> +
>>>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
>>>> +	if (ret < 0 || arg.ret != 0) {
>>>> +		dev_err(tee_rproc_ctx->dev,
>>>> +			"TA_RPROC_FW_CMD_START_FW invoke failed TEE err: %x, ret:%x\n",
>>>> +			arg.ret, ret);
>>>> +		if (!ret)
>>>> +			ret = -EIO;
>>>> +	}
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tee_rproc_start);
>>>> +
>>>> +int tee_rproc_stop(struct rproc *rproc)
>>>> +{
>>>> +	struct tee_ioctl_invoke_arg arg;
>>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>>>> +	struct tee_rproc *trproc = rproc->tee_interface;
>>>> +	int ret;
>>>> +
>>>> +	if (!trproc)
>>>> +		return -EINVAL;
>>>> +
>>>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_STOP_FW, &arg, param, 0);
>>>> +
>>>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
>>>> +	if (ret < 0 || arg.ret != 0) {
>>>> +		dev_err(tee_rproc_ctx->dev,
>>>> +			"TA_RPROC_FW_CMD_STOP_FW invoke failed TEE err: %x, ret:%x\n",
>>>> +			arg.ret, ret);
>>>> +		if (!ret)
>>>> +			ret = -EIO;
>>>> +	}
>>>> +
>>>> +	if (!rproc->table_ptr)
>>>> +		return ret;
>>>> +
>>>> +	iounmap(trproc->rsc_table);
>>>> +	trproc->rsc_table = NULL;
>>>> +	rproc->table_ptr = NULL;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tee_rproc_stop);
>>>> +
>>>> +static const struct tee_client_device_id stm32_tee_rproc_id_table[] = {
>>>> +	{UUID_INIT(0x80a4c275, 0x0a47, 0x4905,
>>>> +		   0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
>>>> +	{}
>>>> +};
>>>> +
>>>> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, unsigned int rproc_id)
>>>> +{
>>>> +	struct tee_client_device *tee_device;
>>>> +	struct tee_ioctl_open_session_arg sess_arg;
>>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
>>>> +	struct tee_rproc *trproc;
>>>> +	int ret;
>>>> +
>>>> +	/*
>>>> +	 * Test if the device has been probed by the TEE bus. In case of failure, we ignore the
>>>> +	 * reason. The bus could be not yet probed or the service not available in the secure
>>>> +	 * firmware.The assumption in such a case is that the TEE remoteproc is not probed.
>>>> +	 */
>>>> +	if (!tee_rproc_ctx)
>>>> +		return ERR_PTR(-EPROBE_DEFER);
>>>> +
>>>> +	trproc =  devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
>>>> +	if (!trproc)
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +
>>>> +	tee_device = to_tee_client_device(tee_rproc_ctx->dev);
>>>> +	memset(&sess_arg, 0, sizeof(sess_arg));
>>>> +
>>>> +	memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
>>>> +
>>>> +	sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
>>>> +	sess_arg.num_params = 1;
>>>> +
>>>> +	param[0] = (struct tee_param) {
>>>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
>>>> +		.u.value.a = rproc_id,
>>>> +	};
>>>> +
>>>> +	ret = tee_client_open_session(tee_rproc_ctx->tee_ctx, &sess_arg, param);
>>>> +	if (ret < 0 || sess_arg.ret != 0) {
>>>> +		dev_err(dev, "tee_client_open_session failed, err: %x\n", sess_arg.ret);
>>>> +		return ERR_PTR(-EINVAL);
>>>> +	}
>>>> +
>>>> +	trproc->parent =  dev;
>>>> +	trproc->rproc_id = rproc_id;
>>>> +	trproc->session_id = sess_arg.session;
>>>> +
>>>> +	trproc->rproc = rproc;
>>>> +	rproc->tee_interface = trproc;
>>>> +
>>>> +	list_add_tail(&trproc->node, &tee_rproc_ctx->sessions);
>>>> +
>>>> +	return trproc;
>>>
>>> Once this function was called by a client, what prevents a user from unloading
>>> the tee_remoteproc module and breaking everything?
>>
>> Good point! seems better toremove the module build capability
>>
> 
> I was thinking more along the lines of try_module_get() and module_put() to
> avoid bloating the core.
> 
>> Thanks,
>> Arnaud
>>
>>>
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tee_rproc_register);
>>>> +
>>>> +int tee_rproc_unregister(struct tee_rproc *trproc)
>>>> +{
>>>
>>> If you pass a struct_rproc instead of a struct tee_rproc there is no need for
>>> tee_rproc::rproc, which is only ever used in this function.
>>>
>>>
>>>> +	struct rproc *rproc = trproc->rproc;
>>>> +	int ret;
>>>> +
>>>> +	ret = tee_client_close_session(tee_rproc_ctx->tee_ctx, trproc->session_id);
>>>> +	if (ret < 0)
>>>> +		dev_err(trproc->parent,	"tee_client_close_session failed, err: %x\n", ret);
>>>> +
>>>> +	list_del(&trproc->node);
>>>> +	rproc->tee_interface = NULL;
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tee_rproc_unregister);
>>>> +
>>>> +static int tee_rproc_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
>>>> +{
>>>> +	/* Today we support only the OP-TEE, could be extend to other tees */
>>>> +	return (ver->impl_id == TEE_IMPL_ID_OPTEE);
>>>> +}
>>>> +
>>>> +static int tee_rproc_probe(struct device *dev)
>>>> +{
>>>> +	struct tee_context *tee_ctx;
>>>> +	int ret;
>>>> +
>>>> +	/* Open context with TEE driver */
>>>> +	tee_ctx = tee_client_open_context(NULL, tee_rproc_ctx_match, NULL, NULL);
>>>> +	if (IS_ERR(tee_ctx))
>>>> +		return PTR_ERR(tee_ctx);
>>>> +
>>>> +	tee_rproc_ctx = devm_kzalloc(dev, sizeof(*tee_ctx), GFP_KERNEL);
>>>> +	if (!tee_rproc_ctx) {
>>>> +		ret = -ENOMEM;
>>>> +		goto err;
>>>> +	}
>>>> +
>>>> +	tee_rproc_ctx->dev = dev;
>>>> +	tee_rproc_ctx->tee_ctx = tee_ctx;
>>>> +	INIT_LIST_HEAD(&tee_rproc_ctx->sessions);
>>>> +
>>>> +	return 0;
>>>> +err:
>>>> +	tee_client_close_context(tee_ctx);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int tee_rproc_remove(struct device *dev)
>>>> +{
>>>> +	struct tee_rproc *entry, *tmp;
>>>> +
>>>> +	list_for_each_entry_safe(entry, tmp, &tee_rproc_ctx->sessions, node) {
>>>> +		tee_client_close_session(tee_rproc_ctx->tee_ctx, entry->session_id);
>>>> +		list_del(&entry->node);
>>>> +		if (entry->rsc_table)
>>>> +			iounmap(entry->rsc_table);
>>>> +		kfree(entry);
>>>> +	}
>>>> +
>>>> +	tee_client_close_context(tee_rproc_ctx->tee_ctx);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +MODULE_DEVICE_TABLE(tee, stm32_tee_rproc_id_table);
>>>> +
>>>> +static struct tee_client_driver tee_rproc_fw_driver = {
>>>> +	.id_table	= stm32_tee_rproc_id_table,
>>>> +	.driver		= {
>>>> +		.name		= KBUILD_MODNAME,
>>>> +		.bus		= &tee_bus_type,
>>>> +		.probe		= tee_rproc_probe,
>>>> +		.remove		= tee_rproc_remove,
>>>> +	},
>>>> +};
>>>> +
>>>> +static int __init tee_rproc_fw_mod_init(void)
>>>> +{
>>>> +	return driver_register(&tee_rproc_fw_driver.driver);
>>>> +}
>>>> +
>>>> +static void __exit tee_rproc_fw_mod_exit(void)
>>>> +{
>>>> +	driver_unregister(&tee_rproc_fw_driver.driver);
>>>> +}
>>>> +
>>>> +module_init(tee_rproc_fw_mod_init);
>>>> +module_exit(tee_rproc_fw_mod_exit);
>>>> +
>>>> +MODULE_DESCRIPTION(" TEE remote processor control driver");
>>>> +MODULE_LICENSE("GPL");
>>>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>>>> index b4795698d8c2..8b678009e481 100644
>>>> --- a/include/linux/remoteproc.h
>>>> +++ b/include/linux/remoteproc.h
>>>> @@ -503,6 +503,8 @@ enum rproc_features {
>>>>  	RPROC_MAX_FEATURES,
>>>>  };
>>>>  
>>>> +struct tee_rproc;
>>>> +
>>>>  /**
>>>>   * struct rproc - represents a physical remote processor device
>>>>   * @node: list node of this rproc object
>>>> @@ -545,6 +547,7 @@ enum rproc_features {
>>>>   * @cdev: character device of the rproc
>>>>   * @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release
>>>>   * @features: indicate remoteproc features
>>>> + * @tee_interface: pointer to the remoteproc tee context
>>>>   */
>>>>  struct rproc {
>>>>  	struct list_head node;
>>>> @@ -586,6 +589,7 @@ struct rproc {
>>>>  	struct cdev cdev;
>>>>  	bool cdev_put_on_release;
>>>>  	DECLARE_BITMAP(features, RPROC_MAX_FEATURES);
>>>> +	struct tee_rproc *tee_interface;
>>>>  };
>>>>  
>>>>  /**
>>>> diff --git a/include/linux/tee_remoteproc.h b/include/linux/tee_remoteproc.h
>>>> new file mode 100644
>>>> index 000000000000..571e47190d02
>>>> --- /dev/null
>>>> +++ b/include/linux/tee_remoteproc.h
>>>> @@ -0,0 +1,112 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>>> +/*
>>>> + * Copyright(c) 2024 STMicroelectronics - All Rights Reserved
>>>> + */
>>>> +
>>>> +#ifndef TEE_REMOTEPROC_H
>>>> +#define TEE_REMOTEPROC_H
>>>> +
>>>> +#include <linux/tee_drv.h>
>>>> +#include <linux/firmware.h>
>>>> +#include <linux/remoteproc.h>
>>>> +
>>>> +struct rproc;
>>>> +
>>>> +/**
>>>> + * struct tee_rproc - TEE remoteproc structure
>>>> + * @node:		Reference in list
>>>> + * @rproc:		Remoteproc reference
>>>> + * @parent:		Parent device
>>>> + * @rproc_id:		Identifier of the target firmware
>>>> + * @session_id:		TEE session identifier
>>>> + * @rsc_table:		Resource table virtual address.
>>>> + */
>>>> +struct tee_rproc {
>>>> +	struct list_head node;
>>>> +	struct rproc *rproc;
>>>> +	struct device *parent;
>>>> +	u32 rproc_id;
>>>> +	u32 session_id;
>>>> +	struct resource_table *rsc_table;
>>>> +};
>>>> +
>>>> +#if IS_REACHABLE(CONFIG_TEE_REMOTEPROC)
>>>> +
>>>> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
>>>> +				     unsigned int rproc_id);
>>>> +int tee_rproc_unregister(struct tee_rproc *trproc);
>>>> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw);
>>>> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw);
>>>> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz);
>>>> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
>>>> +						       const struct firmware *fw);
>>>> +int tee_rproc_start(struct rproc *rproc);
>>>> +int tee_rproc_stop(struct rproc *rproc);
>>>> +
>>>> +#else
>>>> +
>>>> +static inline struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
>>>> +						   unsigned int rproc_id)
>>>> +{
>>>> +	return ERR_PTR(-ENODEV);
>>>> +}
>>>> +
>>>> +static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
>>>> +{
>>>> +	/* This shouldn't be possible */
>>>> +	WARN_ON(1);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static inline int tee_rproc_unregister(struct tee_rproc *trproc)
>>>> +{
>>>> +	/* This shouldn't be possible */
>>>> +	WARN_ON(1);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static inline int tee_rproc_load_fw(struct rproc *rproc,  const struct firmware *fw)
>>>> +{
>>>> +	/* This shouldn't be possible */
>>>> +	WARN_ON(1);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static inline int tee_rproc_start(struct rproc *rproc)
>>>> +{
>>>> +	/* This shouldn't be possible */
>>>> +	WARN_ON(1);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static inline int tee_rproc_stop(struct rproc *rproc)
>>>> +{
>>>> +	/* This shouldn't be possible */
>>>> +	WARN_ON(1);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static inline struct resource_table *
>>>> +tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
>>>> +{
>>>> +	/* This shouldn't be possible */
>>>> +	WARN_ON(1);
>>>> +
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +static inline struct resource_table *
>>>> +tee_rproc_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
>>>> +{
>>>> +	/* This shouldn't be possible */
>>>> +	WARN_ON(1);
>>>> +
>>>> +	return NULL;
>>>> +}
>>>> +#endif /* CONFIG_TEE_REMOTEPROC */
>>>> +#endif /* TEE_REMOTEPROC_H */
>>>> -- 
>>>> 2.25.1
>>>>
Arnaud POULIQUEN March 29, 2024, 10:57 a.m. UTC | #9
On 3/27/24 18:14, Mathieu Poirier wrote:
> On Tue, Mar 26, 2024 at 08:31:33PM +0100, Arnaud POULIQUEN wrote:
>>
>>
>> On 3/25/24 17:51, Mathieu Poirier wrote:
>>> On Fri, Mar 08, 2024 at 03:47:08PM +0100, Arnaud Pouliquen wrote:
>>>> The new TEE remoteproc device is used to manage remote firmware in a
>>>> secure, trusted context. The 'st,stm32mp1-m4-tee' compatibility is
>>>> introduced to delegate the loading of the firmware to the trusted
>>>> execution context. In such cases, the firmware should be signed and
>>>> adhere to the image format defined by the TEE.
>>>>
>>>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>>>> ---
>>>> Updates from V3:
>>>> - remove support of the attach use case. Will be addressed in a separate
>>>>   thread,
>>>> - add st_rproc_tee_ops::parse_fw ops,
>>>> - inverse call of devm_rproc_alloc()and tee_rproc_register() to manage cross
>>>>   reference between the rproc struct and the tee_rproc struct in tee_rproc.c.
>>>> ---
>>>>  drivers/remoteproc/stm32_rproc.c | 60 +++++++++++++++++++++++++++++---
>>>>  1 file changed, 56 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
>>>> index 8cd838df4e92..13df33c78aa2 100644
>>>> --- a/drivers/remoteproc/stm32_rproc.c
>>>> +++ b/drivers/remoteproc/stm32_rproc.c
>>>> @@ -20,6 +20,7 @@
>>>>  #include <linux/remoteproc.h>
>>>>  #include <linux/reset.h>
>>>>  #include <linux/slab.h>
>>>> +#include <linux/tee_remoteproc.h>
>>>>  #include <linux/workqueue.h>
>>>>  
>>>>  #include "remoteproc_internal.h"
>>>> @@ -49,6 +50,9 @@
>>>>  #define M4_STATE_STANDBY	4
>>>>  #define M4_STATE_CRASH		5
>>>>  
>>>> +/* Remote processor unique identifier aligned with the Trusted Execution Environment definitions */
>>>
>>> Why is this the case?  At least from the kernel side it is possible to call
>>> tee_rproc_register() with any kind of value, why is there a need to be any
>>> kind of alignment with the TEE?
>>
>>
>> The use of the proc_id is to identify a processor in case of multi co-processors.
>>
> 
> That is well understood.
> 
>> For instance we can have a system with A DSP and a modem. We would use the same
>> TEE service, but
> 
> That too.
> 
>> the TEE driver will probably be different, same for the signature key.
> 
> What TEE driver are we talking about here?

In OP-TEE remoteproc frameork is divided in 2 or  3 layers:

- the remoteproc Trusted Application (TA) [1] which is platform agnostic
- The remoteproc Pseudo Trusted Application (PTA) [2] which is platform
dependent and can rely on the proc ID to retrieve the context.
- the remoteproc driver (optional for some platforms) [3], which is in charge
 of DT parsing and platform configuration.

Here TEE driver can be interpreted by remote PTA and/or platform driver.

[1]
https://elixir.bootlin.com/op-tee/latest/source/ta/remoteproc/src/remoteproc_core.c
[2]
https://elixir.bootlin.com/op-tee/latest/source/core/pta/stm32mp/remoteproc_pta.c
[3]
https://elixir.bootlin.com/op-tee/latest/source/core/drivers/remoteproc/stm32_remoteproc.c

> 
>> In such case the proc ID allows to identify the the processor you want to address.
>>
> 
> That too is well understood, but there is no alignment needed with the TEE, i.e
> the TEE application is not expecting a value of '0'.  We could set
> STM32_MP1_M4_PROC_ID to 0xDEADBEEF and things would work.  This driver won't go
> anywhere for as long as it is not the case.


Here I suppose that you do not challenge the rproc_ID use in general, but for
the stm32mp1 platform as we have only one remote processor. I'm right?

In OP-TEE the check is done here:
https://elixir.bootlin.com/op-tee/latest/source/core/drivers/remoteproc/stm32_remoteproc.c#L64

If driver does not register the proc ID an error is returned indicating that the
feature is not supported.

In case of stm32mp1 yes we could consider it as useless as we have only one
remote proc.

Nevertheless I can not guaranty that a customer will not add an external
companion processor that uses OP-TEE to authenticate the associated firmware. As
the trusted Application is the unique entry point. he will need the proc_id to
identify the target at PTA level.

So from my point of view having a proc ID on stm32MP1 (and on stm32mp2 that will
reuse same driver) aligned between Linux and OP-TEE is useful.

That said using a TEE_REMOTEPROC_DEFAULT_ID is something that could be
more generic (for linux and OP-TEE). This ID could be reuse in the stm32mp
driver and platform drivers with an unique internal remote processor.

It that solution would be ok for you?

Regards,
Arnaud


> 
>>
>>>
>>>> +#define STM32_MP1_M4_PROC_ID    0
>>>> +
>>>>  struct stm32_syscon {
>>>>  	struct regmap *map;
>>>>  	u32 reg;
>>>> @@ -257,6 +261,19 @@ static int stm32_rproc_release(struct rproc *rproc)
>>>>  	return 0;
>>>>  }
>>>>  
>>>> +static int stm32_rproc_tee_stop(struct rproc *rproc)
>>>> +{
>>>> +	int err;
>>>> +
>>>> +	stm32_rproc_request_shutdown(rproc);
>>>> +
>>>> +	err = tee_rproc_stop(rproc);
>>>> +	if (err)
>>>> +		return err;
>>>> +
>>>> +	return stm32_rproc_release(rproc);
>>>> +}
>>>> +
>>>>  static int stm32_rproc_prepare(struct rproc *rproc)
>>>>  {
>>>>  	struct device *dev = rproc->dev.parent;
>>>> @@ -693,8 +710,19 @@ static const struct rproc_ops st_rproc_ops = {
>>>>  	.get_boot_addr	= rproc_elf_get_boot_addr,
>>>>  };
>>>>  
>>>> +static const struct rproc_ops st_rproc_tee_ops = {
>>>> +	.prepare	= stm32_rproc_prepare,
>>>> +	.start		= tee_rproc_start,
>>>> +	.stop		= stm32_rproc_tee_stop,
>>>> +	.kick		= stm32_rproc_kick,
>>>> +	.load		= tee_rproc_load_fw,
>>>> +	.parse_fw	= tee_rproc_parse_fw,
>>>> +	.find_loaded_rsc_table = tee_rproc_find_loaded_rsc_table,
>>>> +};
>>>> +
>>>>  static const struct of_device_id stm32_rproc_match[] = {
>>>> -	{ .compatible = "st,stm32mp1-m4" },
>>>> +	{.compatible = "st,stm32mp1-m4",},
>>>> +	{.compatible = "st,stm32mp1-m4-tee",},
>>>>  	{},
>>>>  };
>>>>  MODULE_DEVICE_TABLE(of, stm32_rproc_match);
>>>> @@ -853,6 +881,7 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>>>  	struct device *dev = &pdev->dev;
>>>>  	struct stm32_rproc *ddata;
>>>>  	struct device_node *np = dev->of_node;
>>>> +	struct tee_rproc *trproc = NULL;
>>>>  	struct rproc *rproc;
>>>>  	unsigned int state;
>>>>  	int ret;
>>>> @@ -861,9 +890,26 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>>>  	if (ret)
>>>>  		return ret;
>>>>  
>>>> -	rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
>>>> -	if (!rproc)
>>>> -		return -ENOMEM;
>>>> +	if (of_device_is_compatible(np, "st,stm32mp1-m4-tee")) {
>>>> +		/*
>>>> +		 * Delegate the firmware management to the secure context.
>>>> +		 * The firmware loaded has to be signed.
>>>> +		 */
>>>> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
>>>> +		if (!rproc)
>>>> +			return -ENOMEM;
>>>> +
>>>> +		trproc = tee_rproc_register(dev, rproc, STM32_MP1_M4_PROC_ID);
>>>> +		if (IS_ERR(trproc)) {
>>>> +			dev_err_probe(dev, PTR_ERR(trproc),
>>>> +				      "signed firmware not supported by TEE\n");
>>>> +			return PTR_ERR(trproc);
>>>> +		}
>>>> +	} else {
>>>> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
>>>> +		if (!rproc)
>>>> +			return -ENOMEM;
>>>> +	}
>>>>  
>>>>  	ddata = rproc->priv;
>>>>  
>>>> @@ -915,6 +961,9 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>>>  		dev_pm_clear_wake_irq(dev);
>>>>  		device_init_wakeup(dev, false);
>>>>  	}
>>>> +	if (trproc)
>>>
>>>         if (rproc->tee_interface)
>>>
>>>
>>> I am done reviewing this set.
>>
>> Thank for your review!
>> Arnaud
>>
>>>
>>> Thanks,
>>> Mathieu
>>>
>>>> +		tee_rproc_unregister(trproc);
>>>> +
>>>>  	return ret;
>>>>  }
>>>>  
>>>> @@ -935,6 +984,9 @@ static void stm32_rproc_remove(struct platform_device *pdev)
>>>>  		dev_pm_clear_wake_irq(dev);
>>>>  		device_init_wakeup(dev, false);
>>>>  	}
>>>> +	if (rproc->tee_interface)
>>>> +		tee_rproc_unregister(rproc->tee_interface);
>>>> +
>>>>  }
>>>>  
>>>>  static int stm32_rproc_suspend(struct device *dev)
>>>> -- 
>>>> 2.25.1
>>>>
Mathieu Poirier April 1, 2024, 3:46 p.m. UTC | #10
On Fri, Mar 29, 2024 at 11:57:43AM +0100, Arnaud POULIQUEN wrote:
> 
> 
> On 3/27/24 18:14, Mathieu Poirier wrote:
> > On Tue, Mar 26, 2024 at 08:31:33PM +0100, Arnaud POULIQUEN wrote:
> >>
> >>
> >> On 3/25/24 17:51, Mathieu Poirier wrote:
> >>> On Fri, Mar 08, 2024 at 03:47:08PM +0100, Arnaud Pouliquen wrote:
> >>>> The new TEE remoteproc device is used to manage remote firmware in a
> >>>> secure, trusted context. The 'st,stm32mp1-m4-tee' compatibility is
> >>>> introduced to delegate the loading of the firmware to the trusted
> >>>> execution context. In such cases, the firmware should be signed and
> >>>> adhere to the image format defined by the TEE.
> >>>>
> >>>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> >>>> ---
> >>>> Updates from V3:
> >>>> - remove support of the attach use case. Will be addressed in a separate
> >>>>   thread,
> >>>> - add st_rproc_tee_ops::parse_fw ops,
> >>>> - inverse call of devm_rproc_alloc()and tee_rproc_register() to manage cross
> >>>>   reference between the rproc struct and the tee_rproc struct in tee_rproc.c.
> >>>> ---
> >>>>  drivers/remoteproc/stm32_rproc.c | 60 +++++++++++++++++++++++++++++---
> >>>>  1 file changed, 56 insertions(+), 4 deletions(-)
> >>>>
> >>>> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
> >>>> index 8cd838df4e92..13df33c78aa2 100644
> >>>> --- a/drivers/remoteproc/stm32_rproc.c
> >>>> +++ b/drivers/remoteproc/stm32_rproc.c
> >>>> @@ -20,6 +20,7 @@
> >>>>  #include <linux/remoteproc.h>
> >>>>  #include <linux/reset.h>
> >>>>  #include <linux/slab.h>
> >>>> +#include <linux/tee_remoteproc.h>
> >>>>  #include <linux/workqueue.h>
> >>>>  
> >>>>  #include "remoteproc_internal.h"
> >>>> @@ -49,6 +50,9 @@
> >>>>  #define M4_STATE_STANDBY	4
> >>>>  #define M4_STATE_CRASH		5
> >>>>  
> >>>> +/* Remote processor unique identifier aligned with the Trusted Execution Environment definitions */
> >>>
> >>> Why is this the case?  At least from the kernel side it is possible to call
> >>> tee_rproc_register() with any kind of value, why is there a need to be any
> >>> kind of alignment with the TEE?
> >>
> >>
> >> The use of the proc_id is to identify a processor in case of multi co-processors.
> >>
> > 
> > That is well understood.
> > 
> >> For instance we can have a system with A DSP and a modem. We would use the same
> >> TEE service, but
> > 
> > That too.
> > 
> >> the TEE driver will probably be different, same for the signature key.
> > 
> > What TEE driver are we talking about here?
> 
> In OP-TEE remoteproc frameork is divided in 2 or  3 layers:
> 
> - the remoteproc Trusted Application (TA) [1] which is platform agnostic
> - The remoteproc Pseudo Trusted Application (PTA) [2] which is platform
> dependent and can rely on the proc ID to retrieve the context.
> - the remoteproc driver (optional for some platforms) [3], which is in charge
>  of DT parsing and platform configuration.
> 

That part makes sense.

> Here TEE driver can be interpreted by remote PTA and/or platform driver.
>

I have to guess PTA means "Platform Trusted Application" but I have no
guarantee, adding to the level of (already high) confusion brought on by this
patchset.

> [1]
> https://elixir.bootlin.com/op-tee/latest/source/ta/remoteproc/src/remoteproc_core.c
> [2]
> https://elixir.bootlin.com/op-tee/latest/source/core/pta/stm32mp/remoteproc_pta.c
> [3]
> https://elixir.bootlin.com/op-tee/latest/source/core/drivers/remoteproc/stm32_remoteproc.c
> 
> > 
> >> In such case the proc ID allows to identify the the processor you want to address.
> >>
> > 
> > That too is well understood, but there is no alignment needed with the TEE, i.e
> > the TEE application is not expecting a value of '0'.  We could set
> > STM32_MP1_M4_PROC_ID to 0xDEADBEEF and things would work.  This driver won't go
> > anywhere for as long as it is not the case.
> 
> 
> Here I suppose that you do not challenge the rproc_ID use in general, but for
> the stm32mp1 platform as we have only one remote processor. I'm right?

That is correct - I understand the need for an rproc_ID.  The problem is with
the comment that states that '0' is aligned with the TEE definitions, which in
my head means hard coded value and a big red flag.  What it should say is
"aligned with the TEE device tree definition". 

> 
> In OP-TEE the check is done here:
> https://elixir.bootlin.com/op-tee/latest/source/core/drivers/remoteproc/stm32_remoteproc.c#L64
> 
> If driver does not register the proc ID an error is returned indicating that the
> feature is not supported.
> 
> In case of stm32mp1 yes we could consider it as useless as we have only one
> remote proc.
> 
> Nevertheless I can not guaranty that a customer will not add an external
> companion processor that uses OP-TEE to authenticate the associated firmware. As
> the trusted Application is the unique entry point. he will need the proc_id to
> identify the target at PTA level.
> 
> So from my point of view having a proc ID on stm32MP1 (and on stm32mp2 that will
> reuse same driver) aligned between Linux and OP-TEE is useful.

I agree, for as long as it is not hard coded.  The way remote processors are
discovered in the DT is perfectly acceptable, i.e the first remote processor is
for application X, the second for application Y...

> 
> That said using a TEE_REMOTEPROC_DEFAULT_ID is something that could be
> more generic (for linux and OP-TEE). This ID could be reuse in the stm32mp
> driver and platform drivers with an unique internal remote processor.
> 

I can't find the definition of TEE_REMOTEPROC_DEFAULT_ID anywhere, something
that doesn't help the confusion I referred to above.

> It that solution would be ok for you?
> 
> Regards,
> Arnaud
> 
> 
> > 
> >>
> >>>
> >>>> +#define STM32_MP1_M4_PROC_ID    0
> >>>> +
> >>>>  struct stm32_syscon {
> >>>>  	struct regmap *map;
> >>>>  	u32 reg;
> >>>> @@ -257,6 +261,19 @@ static int stm32_rproc_release(struct rproc *rproc)
> >>>>  	return 0;
> >>>>  }
> >>>>  
> >>>> +static int stm32_rproc_tee_stop(struct rproc *rproc)
> >>>> +{
> >>>> +	int err;
> >>>> +
> >>>> +	stm32_rproc_request_shutdown(rproc);
> >>>> +
> >>>> +	err = tee_rproc_stop(rproc);
> >>>> +	if (err)
> >>>> +		return err;
> >>>> +
> >>>> +	return stm32_rproc_release(rproc);
> >>>> +}
> >>>> +
> >>>>  static int stm32_rproc_prepare(struct rproc *rproc)
> >>>>  {
> >>>>  	struct device *dev = rproc->dev.parent;
> >>>> @@ -693,8 +710,19 @@ static const struct rproc_ops st_rproc_ops = {
> >>>>  	.get_boot_addr	= rproc_elf_get_boot_addr,
> >>>>  };
> >>>>  
> >>>> +static const struct rproc_ops st_rproc_tee_ops = {
> >>>> +	.prepare	= stm32_rproc_prepare,
> >>>> +	.start		= tee_rproc_start,
> >>>> +	.stop		= stm32_rproc_tee_stop,
> >>>> +	.kick		= stm32_rproc_kick,
> >>>> +	.load		= tee_rproc_load_fw,
> >>>> +	.parse_fw	= tee_rproc_parse_fw,
> >>>> +	.find_loaded_rsc_table = tee_rproc_find_loaded_rsc_table,
> >>>> +};
> >>>> +
> >>>>  static const struct of_device_id stm32_rproc_match[] = {
> >>>> -	{ .compatible = "st,stm32mp1-m4" },
> >>>> +	{.compatible = "st,stm32mp1-m4",},
> >>>> +	{.compatible = "st,stm32mp1-m4-tee",},
> >>>>  	{},
> >>>>  };
> >>>>  MODULE_DEVICE_TABLE(of, stm32_rproc_match);
> >>>> @@ -853,6 +881,7 @@ static int stm32_rproc_probe(struct platform_device *pdev)
> >>>>  	struct device *dev = &pdev->dev;
> >>>>  	struct stm32_rproc *ddata;
> >>>>  	struct device_node *np = dev->of_node;
> >>>> +	struct tee_rproc *trproc = NULL;
> >>>>  	struct rproc *rproc;
> >>>>  	unsigned int state;
> >>>>  	int ret;
> >>>> @@ -861,9 +890,26 @@ static int stm32_rproc_probe(struct platform_device *pdev)
> >>>>  	if (ret)
> >>>>  		return ret;
> >>>>  
> >>>> -	rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
> >>>> -	if (!rproc)
> >>>> -		return -ENOMEM;
> >>>> +	if (of_device_is_compatible(np, "st,stm32mp1-m4-tee")) {
> >>>> +		/*
> >>>> +		 * Delegate the firmware management to the secure context.
> >>>> +		 * The firmware loaded has to be signed.
> >>>> +		 */
> >>>> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
> >>>> +		if (!rproc)
> >>>> +			return -ENOMEM;
> >>>> +
> >>>> +		trproc = tee_rproc_register(dev, rproc, STM32_MP1_M4_PROC_ID);
> >>>> +		if (IS_ERR(trproc)) {
> >>>> +			dev_err_probe(dev, PTR_ERR(trproc),
> >>>> +				      "signed firmware not supported by TEE\n");
> >>>> +			return PTR_ERR(trproc);
> >>>> +		}
> >>>> +	} else {
> >>>> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
> >>>> +		if (!rproc)
> >>>> +			return -ENOMEM;
> >>>> +	}
> >>>>  
> >>>>  	ddata = rproc->priv;
> >>>>  
> >>>> @@ -915,6 +961,9 @@ static int stm32_rproc_probe(struct platform_device *pdev)
> >>>>  		dev_pm_clear_wake_irq(dev);
> >>>>  		device_init_wakeup(dev, false);
> >>>>  	}
> >>>> +	if (trproc)
> >>>
> >>>         if (rproc->tee_interface)
> >>>
> >>>
> >>> I am done reviewing this set.
> >>
> >> Thank for your review!
> >> Arnaud
> >>
> >>>
> >>> Thanks,
> >>> Mathieu
> >>>
> >>>> +		tee_rproc_unregister(trproc);
> >>>> +
> >>>>  	return ret;
> >>>>  }
> >>>>  
> >>>> @@ -935,6 +984,9 @@ static void stm32_rproc_remove(struct platform_device *pdev)
> >>>>  		dev_pm_clear_wake_irq(dev);
> >>>>  		device_init_wakeup(dev, false);
> >>>>  	}
> >>>> +	if (rproc->tee_interface)
> >>>> +		tee_rproc_unregister(rproc->tee_interface);
> >>>> +
> >>>>  }
> >>>>  
> >>>>  static int stm32_rproc_suspend(struct device *dev)
> >>>> -- 
> >>>> 2.25.1
> >>>>
Mathieu Poirier April 1, 2024, 3:54 p.m. UTC | #11
On Fri, Mar 29, 2024 at 09:58:11AM +0100, Arnaud POULIQUEN wrote:
> Hello Mathieu,
> 
> On 3/27/24 18:07, Mathieu Poirier wrote:
> > On Tue, Mar 26, 2024 at 08:18:23PM +0100, Arnaud POULIQUEN wrote:
> >> Hello Mathieu,
> >>
> >> On 3/25/24 17:46, Mathieu Poirier wrote:
> >>> On Fri, Mar 08, 2024 at 03:47:05PM +0100, Arnaud Pouliquen wrote:
> >>>> Add a remoteproc TEE (Trusted Execution Environment) driver
> >>>> that will be probed by the TEE bus. If the associated Trusted
> >>>> application is supported on secure part this device offers a client
> >>>
> >>> Device or driver?  I thought I touched on that before.
> >>
> >> Right, I changed the first instance and missed this one
> >>
> >>>
> >>>> interface to load a firmware in the secure part.
> >>>> This firmware could be authenticated by the secure trusted application.
> >>>>
> >>>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> >>>> ---
> >>>> Updates from V3:
> >>>> - rework TEE_REMOTEPROC description in Kconfig
> >>>> - fix some namings
> >>>> - add tee_rproc_parse_fw  to support rproc_ops::parse_fw
> >>>> - add proc::tee_interface;
> >>>> - add rproc struct as parameter of the tee_rproc_register() function
> >>>> ---
> >>>>  drivers/remoteproc/Kconfig          |  10 +
> >>>>  drivers/remoteproc/Makefile         |   1 +
> >>>>  drivers/remoteproc/tee_remoteproc.c | 434 ++++++++++++++++++++++++++++
> >>>>  include/linux/remoteproc.h          |   4 +
> >>>>  include/linux/tee_remoteproc.h      | 112 +++++++
> >>>>  5 files changed, 561 insertions(+)
> >>>>  create mode 100644 drivers/remoteproc/tee_remoteproc.c
> >>>>  create mode 100644 include/linux/tee_remoteproc.h
> >>>>
> >>>> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> >>>> index 48845dc8fa85..2cf1431b2b59 100644
> >>>> --- a/drivers/remoteproc/Kconfig
> >>>> +++ b/drivers/remoteproc/Kconfig
> >>>> @@ -365,6 +365,16 @@ config XLNX_R5_REMOTEPROC
> >>>>  
> >>>>  	  It's safe to say N if not interested in using RPU r5f cores.
> >>>>  
> >>>> +
> >>>> +config TEE_REMOTEPROC
> >>>> +	tristate "remoteproc support by a TEE application"
> >>>
> >>> s/remoteproc/Remoteproc
> >>>
> >>>> +	depends on OPTEE
> >>>> +	help
> >>>> +	  Support a remote processor with a TEE application. The Trusted
> >>>> +	  Execution Context is responsible for loading the trusted firmware
> >>>> +	  image and managing the remote processor's lifecycle.
> >>>> +	  This can be either built-in or a loadable module.
> >>>> +
> >>>>  endif # REMOTEPROC
> >>>>  
> >>>>  endmenu
> >>>> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
> >>>> index 91314a9b43ce..fa8daebce277 100644
> >>>> --- a/drivers/remoteproc/Makefile
> >>>> +++ b/drivers/remoteproc/Makefile
> >>>> @@ -36,6 +36,7 @@ obj-$(CONFIG_RCAR_REMOTEPROC)		+= rcar_rproc.o
> >>>>  obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
> >>>>  obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
> >>>>  obj-$(CONFIG_STM32_RPROC)		+= stm32_rproc.o
> >>>> +obj-$(CONFIG_TEE_REMOTEPROC)		+= tee_remoteproc.o
> >>>>  obj-$(CONFIG_TI_K3_DSP_REMOTEPROC)	+= ti_k3_dsp_remoteproc.o
> >>>>  obj-$(CONFIG_TI_K3_R5_REMOTEPROC)	+= ti_k3_r5_remoteproc.o
> >>>>  obj-$(CONFIG_XLNX_R5_REMOTEPROC)	+= xlnx_r5_remoteproc.o
> >>>> diff --git a/drivers/remoteproc/tee_remoteproc.c b/drivers/remoteproc/tee_remoteproc.c
> >>>> new file mode 100644
> >>>> index 000000000000..c855210e52e3
> >>>> --- /dev/null
> >>>> +++ b/drivers/remoteproc/tee_remoteproc.c
> >>>> @@ -0,0 +1,434 @@
> >>>> +// SPDX-License-Identifier: GPL-2.0-or-later
> >>>> +/*
> >>>> + * Copyright (C) STMicroelectronics 2024 - All Rights Reserved
> >>>> + * Author: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> >>>> + */
> >>>> +
> >>>> +#include <linux/firmware.h>
> >>>> +#include <linux/io.h>
> >>>> +#include <linux/module.h>
> >>>> +#include <linux/remoteproc.h>
> >>>> +#include <linux/slab.h>
> >>>> +#include <linux/tee_drv.h>
> >>>> +#include <linux/tee_remoteproc.h>
> >>>> +
> >>>> +#include "remoteproc_internal.h"
> >>>> +
> >>>> +#define MAX_TEE_PARAM_ARRY_MEMBER	4
> >>>> +
> >>>> +/*
> >>>> + * Authentication of the firmware and load in the remote processor memory
> >>>> + *
> >>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >>>> + * [in]	 params[1].memref:	buffer containing the image of the buffer
> >>>> + */
> >>>> +#define TA_RPROC_FW_CMD_LOAD_FW		1
> >>>> +
> >>>> +/*
> >>>> + * Start the remote processor
> >>>> + *
> >>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >>>> + */
> >>>> +#define TA_RPROC_FW_CMD_START_FW	2
> >>>> +
> >>>> +/*
> >>>> + * Stop the remote processor
> >>>> + *
> >>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >>>> + */
> >>>> +#define TA_RPROC_FW_CMD_STOP_FW		3
> >>>> +
> >>>> +/*
> >>>> + * Return the address of the resource table, or 0 if not found
> >>>> + * No check is done to verify that the address returned is accessible by
> >>>> + * the non secure context. If the resource table is loaded in a protected
> >>>> + * memory the access by the non secure context will lead to a data abort.
> >>>> + *
> >>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >>>> + * [out]  params[1].value.a:	32bit LSB resource table memory address
> >>>> + * [out]  params[1].value.b:	32bit MSB resource table memory address
> >>>> + * [out]  params[2].value.a:	32bit LSB resource table memory size
> >>>> + * [out]  params[2].value.b:	32bit MSB resource table memory size
> >>>> + */
> >>>> +#define TA_RPROC_FW_CMD_GET_RSC_TABLE	4
> >>>> +
> >>>> +/*
> >>>> + * Return the address of the core dump
> >>>> + *
> >>>> + * [in]  params[0].value.a:	unique 32bit identifier of the remote processor
> >>>> + * [out] params[1].memref:	address of the core dump image if exist,
> >>>> + *				else return Null
> >>>> + */
> >>>> +#define TA_RPROC_FW_CMD_GET_COREDUMP	5
> >>>> +
> >>>> +struct tee_rproc_context {
> >>>> +	struct list_head sessions;
> >>>> +	struct tee_context *tee_ctx;
> >>>> +	struct device *dev;
> >>>> +};
> >>>> +
> >>>> +static struct tee_rproc_context *tee_rproc_ctx;
> >>>> +
> >>>> +static void tee_rproc_prepare_args(struct tee_rproc *trproc, int cmd,
> >>>> +				   struct tee_ioctl_invoke_arg *arg,
> >>>> +				   struct tee_param *param,
> >>>> +				   unsigned int num_params)
> >>>> +{
> >>>> +	memset(arg, 0, sizeof(*arg));
> >>>> +	memset(param, 0, MAX_TEE_PARAM_ARRY_MEMBER * sizeof(*param));
> >>>> +
> >>>> +	arg->func = cmd;
> >>>> +	arg->session = trproc->session_id;
> >>>> +	arg->num_params = num_params + 1;
> >>>> +
> >>>> +	param[0] = (struct tee_param) {
> >>>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> >>>> +		.u.value.a = trproc->rproc_id,
> >>>> +	};
> >>>> +}
> >>>> +
> >>>> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
> >>>> +{
> >>>> +	struct tee_ioctl_invoke_arg arg;
> >>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >>>> +	struct tee_rproc *trproc = rproc->tee_interface;
> >>>> +	struct tee_shm *fw_shm;
> >>>> +	int ret;
> >>>
> >>> Declarations in reverse ascending order here and everywhere in the driver.
> >>> Sometimes it is done properly, sometimes it isn't. 
> >>>
> >>>> +
> >>>> +	if (!trproc)
> >>>> +		return -EINVAL;
> >>>> +
> >>>> +	fw_shm = tee_shm_register_kernel_buf(tee_rproc_ctx->tee_ctx, (void *)fw->data, fw->size);
> >>>> +	if (IS_ERR(fw_shm))
> >>>> +		return PTR_ERR(fw_shm);
> >>>> +
> >>>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_LOAD_FW, &arg, param, 1);
> >>>> +
> >>>> +	/* Provide the address of the firmware image */
> >>>> +	param[1] = (struct tee_param) {
> >>>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
> >>>> +		.u.memref = {
> >>>> +			.shm = fw_shm,
> >>>> +			.size = fw->size,
> >>>> +			.shm_offs = 0,
> >>>> +		},
> >>>> +	};
> >>>> +
> >>>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> >>>> +	if (ret < 0 || arg.ret != 0) {
> >>>> +		dev_err(tee_rproc_ctx->dev,
> >>>> +			"TA_RPROC_FW_CMD_LOAD_FW invoke failed TEE err: %x, ret:%x\n",
> >>>> +			arg.ret, ret);
> >>>> +		if (!ret)
> >>>> +			ret = -EIO;
> >>>> +	}
> >>>> +
> >>>> +	tee_shm_free(fw_shm);
> >>>> +
> >>>> +	return ret;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(tee_rproc_load_fw);
> >>>> +
> >>>> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
> >>>> +{
> >>>> +	struct tee_ioctl_invoke_arg arg;
> >>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >>>> +	struct tee_rproc *trproc = rproc->tee_interface;
> >>>> +	struct resource_table *rsc_table;
> >>>> +	int ret;
> >>>> +
> >>>> +	if (!trproc)
> >>>> +		return ERR_PTR(-EINVAL);
> >>>> +
> >>>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_GET_RSC_TABLE, &arg, param, 2);
> >>>> +
> >>>> +	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> >>>> +	param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> >>>> +
> >>>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> >>>> +	if (ret < 0 || arg.ret != 0) {
> >>>> +		dev_err(tee_rproc_ctx->dev,
> >>>> +			"TA_RPROC_FW_CMD_GET_RSC_TABLE invoke failed TEE err: %x, ret:%x\n",
> >>>> +			arg.ret, ret);
> >>>> +		return ERR_PTR(-EIO);
> >>>> +	}
> >>>> +
> >>>> +	*table_sz = param[2].u.value.a;
> >>>> +
> >>>> +	/* If the size is null no resource table defined in the image */
> >>>> +	if (!*table_sz)
> >>>> +		return NULL;
> >>>> +
> >>>> +	/* Store the resource table address that would be updated by the remote core. */
> >>>> +	rsc_table = ioremap_wc(param[1].u.value.a, *table_sz);
> >>>> +	if (IS_ERR_OR_NULL(rsc_table)) {
> >>>> +		dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %lld+%zx\n",
> >>>> +			param[1].u.value.a, *table_sz);
> >>>> +		return ERR_PTR(-ENOMEM);
> >>>> +	}
> >>>> +
> >>>> +	return rsc_table;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(tee_rproc_get_loaded_rsc_table);
> >>>> +
> >>>> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> >>>> +{
> >>>> +	struct tee_rproc *trproc = rproc->tee_interface;
> >>>> +	struct resource_table *rsc_table;
> >>>> +	size_t table_sz;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = tee_rproc_load_fw(rproc, fw);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
> >>>> +	if (IS_ERR(rsc_table))
> >>>> +		return PTR_ERR(rsc_table);
> >>>> +
> >>>> +	/* Create a copy of the resource table to have same behaviour than the elf loader. */
> >>>> +	rproc->cached_table = kmemdup(rsc_table, table_sz, GFP_KERNEL);
> >>>> +	if (!rproc->cached_table)
> >>>> +		return -ENOMEM;
> >>>
> >>> Why not ->table_ptr and setting ->cached_table to NULL?
> >>
> >> It was my plan preparing this version. But during implementarion it looks
> >> to me that having exactly same behavior than the ELF loader would be
> >> simpler to maintain the remoteproc avoiding to update in the remoteproc core
> >> to manage for the cached resource table (see also my comment below abourt recovery)
> >> That why I propose this implementation
> >>
> >> That said what you proposal should also work (with some updates in
> >> remoteproc_core for the management of the cached table).
> >>
> > 
> > Yes
> > 
> >> So please just comfirm your preference.
> >>
> > 
> > Definitely keep ->cached_table to NULL.  
> > 
> >>>
> >>>> +
> >>>> +	rproc->table_ptr = rproc->cached_table;
> >>>> +	rproc->table_sz = table_sz;
> >>>> +	trproc->rsc_table = rsc_table;
> >>>
> >>> I really don't see why this is needed, please remove and use rproc->table_ptr
> >>> instead.
> >>
> >> I need to store it for the iounmap in tee_rproc_remove.
> > 
> > iounmap(entry->rproc->rsc_table);
> > 
> > What am I missing?
> 
> rproc->rsc_table is a field that can be updated by remoteproc_core.
> How can we garanty in tee_remoteproc that it still points to the mapped resource
> table?

By making sure the core doesn't touch rproc->rsc_table when
rproc->tee_interface is valid.

> As the remoteproc_tee maps the pointer, it seems reliable that it stores it for
> unmap.
> 

Doing so creates a shadow value that is confusing and really hard to maintain
going forward.

> Seems also that I also missed to  handle the case where rproc_fw_boot() fails[3]
> (not done yet).
> 
> [3]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1442
> 
> 
> > 
> >>
> >>>
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(tee_rproc_parse_fw);
> >>>> +
> >>>> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
> >>>> +						       const struct firmware *fw)
> >>>> +{
> >>>> +	struct tee_rproc *trproc = rproc->tee_interface;
> >>>> +	struct resource_table *rsc_table;
> >>>> +	size_t table_sz;
> >>>> +
> >>>> +	if (!trproc)
> >>>> +		return ERR_PTR(-EINVAL);
> >>>> +
> >>>> +	/* Check if the resourse table has already been obtained in tee_rproc_parse_fw() */
> >>>> +	if (trproc->rsc_table)
> >>>> +		return trproc->rsc_table;
> >>>
> >>> Again, why not simply use rproc->rsc_table?  This function should only return
> >>> the resource table that was set in tee_rproc_parse_fw(). 
> >>
> >> In case of recovery rproc->_rsc_table point to the cached table [1]
> >  
> > In [1], on line 1554, add a check for rproc->tee_interface and if it is valid
> > call rproc_find_loaded_rsc_table(). 
> > 
> >> and we need to reapply the configuration in rproc_start() called during the
> >> recovery[2]
> > 
> > 1) Rename rproc_set_rsc_table() to rproc_set_rsc_table_on_attach()
> > 2) Introduce a new function called rproc_set_rsc_table_on_start()
> > 3) Move code from [2], line 1278 to 1292, to that new function.  In the new
> > function, add a check on rproc->tee_interface.  If it is valid then call
> > rproc_find_loaded_rsc_table().
> > 4) in rproc_start(), replace lines 1278 to 1292 with a call to
> > rproc_set_rsc_table_on_start().
> 
> 
> I will try this
> 

Ok

> Thanks!
> Arnaud
> 
> > 
> >> [1]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1586
> >> [2]https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1287
> >>
> >>>
> >>>> +
> >>>> +	rsc_table = tee_rproc_get_loaded_rsc_table(rproc, &table_sz);
> >>>> +	if (IS_ERR(rsc_table))
> >>>> +		return rsc_table;
> >>>> +
> >>>> +	rproc->table_sz = table_sz;
> >>>> +	trproc->rsc_table = rsc_table;
> >>>> +
> >>>> +	return rsc_table;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
> >>>> +
> >>>> +int tee_rproc_start(struct rproc *rproc)
> >>>> +{
> >>>> +	struct tee_ioctl_invoke_arg arg;
> >>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >>>> +	struct tee_rproc *trproc = rproc->tee_interface;
> >>>> +	int ret;
> >>>> +
> >>>> +	if (!trproc)
> >>>> +		return -EINVAL;
> >>>> +
> >>>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_START_FW, &arg, param, 0);
> >>>> +
> >>>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> >>>> +	if (ret < 0 || arg.ret != 0) {
> >>>> +		dev_err(tee_rproc_ctx->dev,
> >>>> +			"TA_RPROC_FW_CMD_START_FW invoke failed TEE err: %x, ret:%x\n",
> >>>> +			arg.ret, ret);
> >>>> +		if (!ret)
> >>>> +			ret = -EIO;
> >>>> +	}
> >>>> +
> >>>> +	return ret;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(tee_rproc_start);
> >>>> +
> >>>> +int tee_rproc_stop(struct rproc *rproc)
> >>>> +{
> >>>> +	struct tee_ioctl_invoke_arg arg;
> >>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >>>> +	struct tee_rproc *trproc = rproc->tee_interface;
> >>>> +	int ret;
> >>>> +
> >>>> +	if (!trproc)
> >>>> +		return -EINVAL;
> >>>> +
> >>>> +	tee_rproc_prepare_args(trproc, TA_RPROC_FW_CMD_STOP_FW, &arg, param, 0);
> >>>> +
> >>>> +	ret = tee_client_invoke_func(tee_rproc_ctx->tee_ctx, &arg, param);
> >>>> +	if (ret < 0 || arg.ret != 0) {
> >>>> +		dev_err(tee_rproc_ctx->dev,
> >>>> +			"TA_RPROC_FW_CMD_STOP_FW invoke failed TEE err: %x, ret:%x\n",
> >>>> +			arg.ret, ret);
> >>>> +		if (!ret)
> >>>> +			ret = -EIO;
> >>>> +	}
> >>>> +
> >>>> +	if (!rproc->table_ptr)
> >>>> +		return ret;
> >>>> +
> >>>> +	iounmap(trproc->rsc_table);
> >>>> +	trproc->rsc_table = NULL;
> >>>> +	rproc->table_ptr = NULL;
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(tee_rproc_stop);
> >>>> +
> >>>> +static const struct tee_client_device_id stm32_tee_rproc_id_table[] = {
> >>>> +	{UUID_INIT(0x80a4c275, 0x0a47, 0x4905,
> >>>> +		   0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
> >>>> +	{}
> >>>> +};
> >>>> +
> >>>> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, unsigned int rproc_id)
> >>>> +{
> >>>> +	struct tee_client_device *tee_device;
> >>>> +	struct tee_ioctl_open_session_arg sess_arg;
> >>>> +	struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> >>>> +	struct tee_rproc *trproc;
> >>>> +	int ret;
> >>>> +
> >>>> +	/*
> >>>> +	 * Test if the device has been probed by the TEE bus. In case of failure, we ignore the
> >>>> +	 * reason. The bus could be not yet probed or the service not available in the secure
> >>>> +	 * firmware.The assumption in such a case is that the TEE remoteproc is not probed.
> >>>> +	 */
> >>>> +	if (!tee_rproc_ctx)
> >>>> +		return ERR_PTR(-EPROBE_DEFER);
> >>>> +
> >>>> +	trproc =  devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
> >>>> +	if (!trproc)
> >>>> +		return ERR_PTR(-ENOMEM);
> >>>> +
> >>>> +	tee_device = to_tee_client_device(tee_rproc_ctx->dev);
> >>>> +	memset(&sess_arg, 0, sizeof(sess_arg));
> >>>> +
> >>>> +	memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> >>>> +
> >>>> +	sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
> >>>> +	sess_arg.num_params = 1;
> >>>> +
> >>>> +	param[0] = (struct tee_param) {
> >>>> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> >>>> +		.u.value.a = rproc_id,
> >>>> +	};
> >>>> +
> >>>> +	ret = tee_client_open_session(tee_rproc_ctx->tee_ctx, &sess_arg, param);
> >>>> +	if (ret < 0 || sess_arg.ret != 0) {
> >>>> +		dev_err(dev, "tee_client_open_session failed, err: %x\n", sess_arg.ret);
> >>>> +		return ERR_PTR(-EINVAL);
> >>>> +	}
> >>>> +
> >>>> +	trproc->parent =  dev;
> >>>> +	trproc->rproc_id = rproc_id;
> >>>> +	trproc->session_id = sess_arg.session;
> >>>> +
> >>>> +	trproc->rproc = rproc;
> >>>> +	rproc->tee_interface = trproc;
> >>>> +
> >>>> +	list_add_tail(&trproc->node, &tee_rproc_ctx->sessions);
> >>>> +
> >>>> +	return trproc;
> >>>
> >>> Once this function was called by a client, what prevents a user from unloading
> >>> the tee_remoteproc module and breaking everything?
> >>
> >> Good point! seems better toremove the module build capability
> >>
> > 
> > I was thinking more along the lines of try_module_get() and module_put() to
> > avoid bloating the core.
> > 
> >> Thanks,
> >> Arnaud
> >>
> >>>
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(tee_rproc_register);
> >>>> +
> >>>> +int tee_rproc_unregister(struct tee_rproc *trproc)
> >>>> +{
> >>>
> >>> If you pass a struct_rproc instead of a struct tee_rproc there is no need for
> >>> tee_rproc::rproc, which is only ever used in this function.
> >>>
> >>>
> >>>> +	struct rproc *rproc = trproc->rproc;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = tee_client_close_session(tee_rproc_ctx->tee_ctx, trproc->session_id);
> >>>> +	if (ret < 0)
> >>>> +		dev_err(trproc->parent,	"tee_client_close_session failed, err: %x\n", ret);
> >>>> +
> >>>> +	list_del(&trproc->node);
> >>>> +	rproc->tee_interface = NULL;
> >>>> +
> >>>> +	return ret;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(tee_rproc_unregister);
> >>>> +
> >>>> +static int tee_rproc_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> >>>> +{
> >>>> +	/* Today we support only the OP-TEE, could be extend to other tees */
> >>>> +	return (ver->impl_id == TEE_IMPL_ID_OPTEE);
> >>>> +}
> >>>> +
> >>>> +static int tee_rproc_probe(struct device *dev)
> >>>> +{
> >>>> +	struct tee_context *tee_ctx;
> >>>> +	int ret;
> >>>> +
> >>>> +	/* Open context with TEE driver */
> >>>> +	tee_ctx = tee_client_open_context(NULL, tee_rproc_ctx_match, NULL, NULL);
> >>>> +	if (IS_ERR(tee_ctx))
> >>>> +		return PTR_ERR(tee_ctx);
> >>>> +
> >>>> +	tee_rproc_ctx = devm_kzalloc(dev, sizeof(*tee_ctx), GFP_KERNEL);
> >>>> +	if (!tee_rproc_ctx) {
> >>>> +		ret = -ENOMEM;
> >>>> +		goto err;
> >>>> +	}
> >>>> +
> >>>> +	tee_rproc_ctx->dev = dev;
> >>>> +	tee_rproc_ctx->tee_ctx = tee_ctx;
> >>>> +	INIT_LIST_HEAD(&tee_rproc_ctx->sessions);
> >>>> +
> >>>> +	return 0;
> >>>> +err:
> >>>> +	tee_client_close_context(tee_ctx);
> >>>> +
> >>>> +	return ret;
> >>>> +}
> >>>> +
> >>>> +static int tee_rproc_remove(struct device *dev)
> >>>> +{
> >>>> +	struct tee_rproc *entry, *tmp;
> >>>> +
> >>>> +	list_for_each_entry_safe(entry, tmp, &tee_rproc_ctx->sessions, node) {
> >>>> +		tee_client_close_session(tee_rproc_ctx->tee_ctx, entry->session_id);
> >>>> +		list_del(&entry->node);
> >>>> +		if (entry->rsc_table)
> >>>> +			iounmap(entry->rsc_table);
> >>>> +		kfree(entry);
> >>>> +	}
> >>>> +
> >>>> +	tee_client_close_context(tee_rproc_ctx->tee_ctx);
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> +MODULE_DEVICE_TABLE(tee, stm32_tee_rproc_id_table);
> >>>> +
> >>>> +static struct tee_client_driver tee_rproc_fw_driver = {
> >>>> +	.id_table	= stm32_tee_rproc_id_table,
> >>>> +	.driver		= {
> >>>> +		.name		= KBUILD_MODNAME,
> >>>> +		.bus		= &tee_bus_type,
> >>>> +		.probe		= tee_rproc_probe,
> >>>> +		.remove		= tee_rproc_remove,
> >>>> +	},
> >>>> +};
> >>>> +
> >>>> +static int __init tee_rproc_fw_mod_init(void)
> >>>> +{
> >>>> +	return driver_register(&tee_rproc_fw_driver.driver);
> >>>> +}
> >>>> +
> >>>> +static void __exit tee_rproc_fw_mod_exit(void)
> >>>> +{
> >>>> +	driver_unregister(&tee_rproc_fw_driver.driver);
> >>>> +}
> >>>> +
> >>>> +module_init(tee_rproc_fw_mod_init);
> >>>> +module_exit(tee_rproc_fw_mod_exit);
> >>>> +
> >>>> +MODULE_DESCRIPTION(" TEE remote processor control driver");
> >>>> +MODULE_LICENSE("GPL");
> >>>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >>>> index b4795698d8c2..8b678009e481 100644
> >>>> --- a/include/linux/remoteproc.h
> >>>> +++ b/include/linux/remoteproc.h
> >>>> @@ -503,6 +503,8 @@ enum rproc_features {
> >>>>  	RPROC_MAX_FEATURES,
> >>>>  };
> >>>>  
> >>>> +struct tee_rproc;
> >>>> +
> >>>>  /**
> >>>>   * struct rproc - represents a physical remote processor device
> >>>>   * @node: list node of this rproc object
> >>>> @@ -545,6 +547,7 @@ enum rproc_features {
> >>>>   * @cdev: character device of the rproc
> >>>>   * @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release
> >>>>   * @features: indicate remoteproc features
> >>>> + * @tee_interface: pointer to the remoteproc tee context
> >>>>   */
> >>>>  struct rproc {
> >>>>  	struct list_head node;
> >>>> @@ -586,6 +589,7 @@ struct rproc {
> >>>>  	struct cdev cdev;
> >>>>  	bool cdev_put_on_release;
> >>>>  	DECLARE_BITMAP(features, RPROC_MAX_FEATURES);
> >>>> +	struct tee_rproc *tee_interface;
> >>>>  };
> >>>>  
> >>>>  /**
> >>>> diff --git a/include/linux/tee_remoteproc.h b/include/linux/tee_remoteproc.h
> >>>> new file mode 100644
> >>>> index 000000000000..571e47190d02
> >>>> --- /dev/null
> >>>> +++ b/include/linux/tee_remoteproc.h
> >>>> @@ -0,0 +1,112 @@
> >>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> >>>> +/*
> >>>> + * Copyright(c) 2024 STMicroelectronics - All Rights Reserved
> >>>> + */
> >>>> +
> >>>> +#ifndef TEE_REMOTEPROC_H
> >>>> +#define TEE_REMOTEPROC_H
> >>>> +
> >>>> +#include <linux/tee_drv.h>
> >>>> +#include <linux/firmware.h>
> >>>> +#include <linux/remoteproc.h>
> >>>> +
> >>>> +struct rproc;
> >>>> +
> >>>> +/**
> >>>> + * struct tee_rproc - TEE remoteproc structure
> >>>> + * @node:		Reference in list
> >>>> + * @rproc:		Remoteproc reference
> >>>> + * @parent:		Parent device
> >>>> + * @rproc_id:		Identifier of the target firmware
> >>>> + * @session_id:		TEE session identifier
> >>>> + * @rsc_table:		Resource table virtual address.
> >>>> + */
> >>>> +struct tee_rproc {
> >>>> +	struct list_head node;
> >>>> +	struct rproc *rproc;
> >>>> +	struct device *parent;
> >>>> +	u32 rproc_id;
> >>>> +	u32 session_id;
> >>>> +	struct resource_table *rsc_table;
> >>>> +};
> >>>> +
> >>>> +#if IS_REACHABLE(CONFIG_TEE_REMOTEPROC)
> >>>> +
> >>>> +struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
> >>>> +				     unsigned int rproc_id);
> >>>> +int tee_rproc_unregister(struct tee_rproc *trproc);
> >>>> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw);
> >>>> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw);
> >>>> +struct resource_table *tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz);
> >>>> +struct resource_table *tee_rproc_find_loaded_rsc_table(struct rproc *rproc,
> >>>> +						       const struct firmware *fw);
> >>>> +int tee_rproc_start(struct rproc *rproc);
> >>>> +int tee_rproc_stop(struct rproc *rproc);
> >>>> +
> >>>> +#else
> >>>> +
> >>>> +static inline struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc,
> >>>> +						   unsigned int rproc_id)
> >>>> +{
> >>>> +	return ERR_PTR(-ENODEV);
> >>>> +}
> >>>> +
> >>>> +static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> >>>> +{
> >>>> +	/* This shouldn't be possible */
> >>>> +	WARN_ON(1);
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> +static inline int tee_rproc_unregister(struct tee_rproc *trproc)
> >>>> +{
> >>>> +	/* This shouldn't be possible */
> >>>> +	WARN_ON(1);
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> +static inline int tee_rproc_load_fw(struct rproc *rproc,  const struct firmware *fw)
> >>>> +{
> >>>> +	/* This shouldn't be possible */
> >>>> +	WARN_ON(1);
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> +static inline int tee_rproc_start(struct rproc *rproc)
> >>>> +{
> >>>> +	/* This shouldn't be possible */
> >>>> +	WARN_ON(1);
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> +static inline int tee_rproc_stop(struct rproc *rproc)
> >>>> +{
> >>>> +	/* This shouldn't be possible */
> >>>> +	WARN_ON(1);
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> +static inline struct resource_table *
> >>>> +tee_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
> >>>> +{
> >>>> +	/* This shouldn't be possible */
> >>>> +	WARN_ON(1);
> >>>> +
> >>>> +	return NULL;
> >>>> +}
> >>>> +
> >>>> +static inline struct resource_table *
> >>>> +tee_rproc_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
> >>>> +{
> >>>> +	/* This shouldn't be possible */
> >>>> +	WARN_ON(1);
> >>>> +
> >>>> +	return NULL;
> >>>> +}
> >>>> +#endif /* CONFIG_TEE_REMOTEPROC */
> >>>> +#endif /* TEE_REMOTEPROC_H */
> >>>> -- 
> >>>> 2.25.1
> >>>>
Arnaud POULIQUEN April 3, 2024, 7:04 a.m. UTC | #12
On 4/1/24 17:46, Mathieu Poirier wrote:
> On Fri, Mar 29, 2024 at 11:57:43AM +0100, Arnaud POULIQUEN wrote:
>>
>>
>> On 3/27/24 18:14, Mathieu Poirier wrote:
>>> On Tue, Mar 26, 2024 at 08:31:33PM +0100, Arnaud POULIQUEN wrote:
>>>>
>>>>
>>>> On 3/25/24 17:51, Mathieu Poirier wrote:
>>>>> On Fri, Mar 08, 2024 at 03:47:08PM +0100, Arnaud Pouliquen wrote:
>>>>>> The new TEE remoteproc device is used to manage remote firmware in a
>>>>>> secure, trusted context. The 'st,stm32mp1-m4-tee' compatibility is
>>>>>> introduced to delegate the loading of the firmware to the trusted
>>>>>> execution context. In such cases, the firmware should be signed and
>>>>>> adhere to the image format defined by the TEE.
>>>>>>
>>>>>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>>>>>> ---
>>>>>> Updates from V3:
>>>>>> - remove support of the attach use case. Will be addressed in a separate
>>>>>>   thread,
>>>>>> - add st_rproc_tee_ops::parse_fw ops,
>>>>>> - inverse call of devm_rproc_alloc()and tee_rproc_register() to manage cross
>>>>>>   reference between the rproc struct and the tee_rproc struct in tee_rproc.c.
>>>>>> ---
>>>>>>  drivers/remoteproc/stm32_rproc.c | 60 +++++++++++++++++++++++++++++---
>>>>>>  1 file changed, 56 insertions(+), 4 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
>>>>>> index 8cd838df4e92..13df33c78aa2 100644
>>>>>> --- a/drivers/remoteproc/stm32_rproc.c
>>>>>> +++ b/drivers/remoteproc/stm32_rproc.c
>>>>>> @@ -20,6 +20,7 @@
>>>>>>  #include <linux/remoteproc.h>
>>>>>>  #include <linux/reset.h>
>>>>>>  #include <linux/slab.h>
>>>>>> +#include <linux/tee_remoteproc.h>
>>>>>>  #include <linux/workqueue.h>
>>>>>>  
>>>>>>  #include "remoteproc_internal.h"
>>>>>> @@ -49,6 +50,9 @@
>>>>>>  #define M4_STATE_STANDBY	4
>>>>>>  #define M4_STATE_CRASH		5
>>>>>>  
>>>>>> +/* Remote processor unique identifier aligned with the Trusted Execution Environment definitions */
>>>>>
>>>>> Why is this the case?  At least from the kernel side it is possible to call
>>>>> tee_rproc_register() with any kind of value, why is there a need to be any
>>>>> kind of alignment with the TEE?
>>>>
>>>>
>>>> The use of the proc_id is to identify a processor in case of multi co-processors.
>>>>
>>>
>>> That is well understood.
>>>
>>>> For instance we can have a system with A DSP and a modem. We would use the same
>>>> TEE service, but
>>>
>>> That too.
>>>
>>>> the TEE driver will probably be different, same for the signature key.
>>>
>>> What TEE driver are we talking about here?
>>
>> In OP-TEE remoteproc frameork is divided in 2 or  3 layers:
>>
>> - the remoteproc Trusted Application (TA) [1] which is platform agnostic
>> - The remoteproc Pseudo Trusted Application (PTA) [2] which is platform
>> dependent and can rely on the proc ID to retrieve the context.
>> - the remoteproc driver (optional for some platforms) [3], which is in charge
>>  of DT parsing and platform configuration.
>>
> 
> That part makes sense.
> 
>> Here TEE driver can be interpreted by remote PTA and/or platform driver.
>>
> 
> I have to guess PTA means "Platform Trusted Application" but I have no
> guarantee, adding to the level of (already high) confusion brought on by this
> patchset.

As mentioned above, PTA is Pseudo Trusted Application. It is an interface
exposed by OP-TEE core to the OP-TEE application.
In this case PTA is used to implement the platform part.
If you need more details about the remoteproc framework in OP-TEE, there is a
link in the to a presentation in the cover letter.

> 
>> [1]
>> https://elixir.bootlin.com/op-tee/latest/source/ta/remoteproc/src/remoteproc_core.c
>> [2]
>> https://elixir.bootlin.com/op-tee/latest/source/core/pta/stm32mp/remoteproc_pta.c
>> [3]
>> https://elixir.bootlin.com/op-tee/latest/source/core/drivers/remoteproc/stm32_remoteproc.c
>>
>>>
>>>> In such case the proc ID allows to identify the the processor you want to address.
>>>>
>>>
>>> That too is well understood, but there is no alignment needed with the TEE, i.e
>>> the TEE application is not expecting a value of '0'.  We could set
>>> STM32_MP1_M4_PROC_ID to 0xDEADBEEF and things would work.  This driver won't go
>>> anywhere for as long as it is not the case.
>>
>>
>> Here I suppose that you do not challenge the rproc_ID use in general, but for
>> the stm32mp1 platform as we have only one remote processor. I'm right?
> 
> That is correct - I understand the need for an rproc_ID.  The problem is with
> the comment that states that '0' is aligned with the TEE definitions, which in
> my head means hard coded value and a big red flag.  What it should say is
> "aligned with the TEE device tree definition". 
> 
>>
>> In OP-TEE the check is done here:
>> https://elixir.bootlin.com/op-tee/latest/source/core/drivers/remoteproc/stm32_remoteproc.c#L64
>>
>> If driver does not register the proc ID an error is returned indicating that the
>> feature is not supported.
>>
>> In case of stm32mp1 yes we could consider it as useless as we have only one
>> remote proc.
>>
>> Nevertheless I can not guaranty that a customer will not add an external
>> companion processor that uses OP-TEE to authenticate the associated firmware. As
>> the trusted Application is the unique entry point. he will need the proc_id to
>> identify the target at PTA level.
>>
>> So from my point of view having a proc ID on stm32MP1 (and on stm32mp2 that will
>> reuse same driver) aligned between Linux and OP-TEE is useful.
> 
> I agree, for as long as it is not hard coded.  The way remote processors are
> discovered in the DT is perfectly acceptable, i.e the first remote processor is
> for application X, the second for application Y...
> 
>>
>> That said using a TEE_REMOTEPROC_DEFAULT_ID is something that could be
>> more generic (for linux and OP-TEE). This ID could be reuse in the stm32mp
>> driver and platform drivers with an unique internal remote processor.
>>
> 
> I can't find the definition of TEE_REMOTEPROC_DEFAULT_ID anywhere, something
> that doesn't help the confusion I referred to above.

The TEE_REMOTEPROC_DEFAULT_ID does not yet exist; it is a proposal.

Nevertheless I also had in mind the addition of a "proc ID" property in the DT.
I will proceed in this way

I think I now have all the information needed to prepare a new revision.
Thanks for the time passed on this series and your advises
Regards,
Arnaud


> 
>> It that solution would be ok for you?
>>
>> Regards,
>> Arnaud
>>
>>
>>>
>>>>
>>>>>
>>>>>> +#define STM32_MP1_M4_PROC_ID    0
>>>>>> +
>>>>>>  struct stm32_syscon {
>>>>>>  	struct regmap *map;
>>>>>>  	u32 reg;
>>>>>> @@ -257,6 +261,19 @@ static int stm32_rproc_release(struct rproc *rproc)
>>>>>>  	return 0;
>>>>>>  }
>>>>>>  
>>>>>> +static int stm32_rproc_tee_stop(struct rproc *rproc)
>>>>>> +{
>>>>>> +	int err;
>>>>>> +
>>>>>> +	stm32_rproc_request_shutdown(rproc);
>>>>>> +
>>>>>> +	err = tee_rproc_stop(rproc);
>>>>>> +	if (err)
>>>>>> +		return err;
>>>>>> +
>>>>>> +	return stm32_rproc_release(rproc);
>>>>>> +}
>>>>>> +
>>>>>>  static int stm32_rproc_prepare(struct rproc *rproc)
>>>>>>  {
>>>>>>  	struct device *dev = rproc->dev.parent;
>>>>>> @@ -693,8 +710,19 @@ static const struct rproc_ops st_rproc_ops = {
>>>>>>  	.get_boot_addr	= rproc_elf_get_boot_addr,
>>>>>>  };
>>>>>>  
>>>>>> +static const struct rproc_ops st_rproc_tee_ops = {
>>>>>> +	.prepare	= stm32_rproc_prepare,
>>>>>> +	.start		= tee_rproc_start,
>>>>>> +	.stop		= stm32_rproc_tee_stop,
>>>>>> +	.kick		= stm32_rproc_kick,
>>>>>> +	.load		= tee_rproc_load_fw,
>>>>>> +	.parse_fw	= tee_rproc_parse_fw,
>>>>>> +	.find_loaded_rsc_table = tee_rproc_find_loaded_rsc_table,
>>>>>> +};
>>>>>> +
>>>>>>  static const struct of_device_id stm32_rproc_match[] = {
>>>>>> -	{ .compatible = "st,stm32mp1-m4" },
>>>>>> +	{.compatible = "st,stm32mp1-m4",},
>>>>>> +	{.compatible = "st,stm32mp1-m4-tee",},
>>>>>>  	{},
>>>>>>  };
>>>>>>  MODULE_DEVICE_TABLE(of, stm32_rproc_match);
>>>>>> @@ -853,6 +881,7 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>>>>>  	struct device *dev = &pdev->dev;
>>>>>>  	struct stm32_rproc *ddata;
>>>>>>  	struct device_node *np = dev->of_node;
>>>>>> +	struct tee_rproc *trproc = NULL;
>>>>>>  	struct rproc *rproc;
>>>>>>  	unsigned int state;
>>>>>>  	int ret;
>>>>>> @@ -861,9 +890,26 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>>>>>  	if (ret)
>>>>>>  		return ret;
>>>>>>  
>>>>>> -	rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
>>>>>> -	if (!rproc)
>>>>>> -		return -ENOMEM;
>>>>>> +	if (of_device_is_compatible(np, "st,stm32mp1-m4-tee")) {
>>>>>> +		/*
>>>>>> +		 * Delegate the firmware management to the secure context.
>>>>>> +		 * The firmware loaded has to be signed.
>>>>>> +		 */
>>>>>> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
>>>>>> +		if (!rproc)
>>>>>> +			return -ENOMEM;
>>>>>> +
>>>>>> +		trproc = tee_rproc_register(dev, rproc, STM32_MP1_M4_PROC_ID);
>>>>>> +		if (IS_ERR(trproc)) {
>>>>>> +			dev_err_probe(dev, PTR_ERR(trproc),
>>>>>> +				      "signed firmware not supported by TEE\n");
>>>>>> +			return PTR_ERR(trproc);
>>>>>> +		}
>>>>>> +	} else {
>>>>>> +		rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
>>>>>> +		if (!rproc)
>>>>>> +			return -ENOMEM;
>>>>>> +	}
>>>>>>  
>>>>>>  	ddata = rproc->priv;
>>>>>>  
>>>>>> @@ -915,6 +961,9 @@ static int stm32_rproc_probe(struct platform_device *pdev)
>>>>>>  		dev_pm_clear_wake_irq(dev);
>>>>>>  		device_init_wakeup(dev, false);
>>>>>>  	}
>>>>>> +	if (trproc)
>>>>>
>>>>>         if (rproc->tee_interface)
>>>>>
>>>>>
>>>>> I am done reviewing this set.
>>>>
>>>> Thank for your review!
>>>> Arnaud
>>>>
>>>>>
>>>>> Thanks,
>>>>> Mathieu
>>>>>
>>>>>> +		tee_rproc_unregister(trproc);
>>>>>> +
>>>>>>  	return ret;
>>>>>>  }
>>>>>>  
>>>>>> @@ -935,6 +984,9 @@ static void stm32_rproc_remove(struct platform_device *pdev)
>>>>>>  		dev_pm_clear_wake_irq(dev);
>>>>>>  		device_init_wakeup(dev, false);
>>>>>>  	}
>>>>>> +	if (rproc->tee_interface)
>>>>>> +		tee_rproc_unregister(rproc->tee_interface);
>>>>>> +
>>>>>>  }
>>>>>>  
>>>>>>  static int stm32_rproc_suspend(struct device *dev)
>>>>>> -- 
>>>>>> 2.25.1
>>>>>>