* [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware
@ 2024-08-30 9:51 Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 1/7] remoteproc: core: Introduce rproc_pa_to_va helper Arnaud Pouliquen
` (6 more replies)
0 siblings, 7 replies; 25+ messages in thread
From: Arnaud Pouliquen @ 2024-08-30 9:51 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
Main updates from version V8[1]:
Add support for tee_rproc_release_fw(), which allows releasing firmware
that has been loaded. This service is used if an error occurs between
the loading of the firmware image and the start of the remote processor.
It is also called on remote processor shutdown.
Associated with this series, an update has been sent to OP-TEE for the
support of the TA_RPROC_CMD_RELEASE_FW TEE command [2].
[1] https://lore.kernel.org/linux-arm-kernel/20240621143759.547793-4-arnaud.pouliquen@foss.st.com/T/
[2]https://github.com/OP-TEE/optee_os/pull/7019
Tested-on: commit 5be63fc19fca ("Linux 6.11-rc5")
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 (7):
remoteproc: core: Introduce rproc_pa_to_va helper
remoteproc: Add TEE support
remoteproc: core: Refactor resource table cleanup into
rproc_release_fw
remoteproc: core: Add TEE interface support for firmware release
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 | 58 ++-
drivers/remoteproc/Kconfig | 10 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/remoteproc_core.c | 77 ++-
drivers/remoteproc/remoteproc_tee.c | 486 ++++++++++++++++++
drivers/remoteproc/stm32_rproc.c | 147 ++++--
include/linux/remoteproc.h | 5 +
include/linux/remoteproc_tee.h | 109 ++++
8 files changed, 836 insertions(+), 57 deletions(-)
create mode 100644 drivers/remoteproc/remoteproc_tee.c
create mode 100644 include/linux/remoteproc_tee.h
base-commit: 5be63fc19fcaa4c236b307420483578a56986a37
--
2.25.1
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v9 1/7] remoteproc: core: Introduce rproc_pa_to_va helper
2024-08-30 9:51 [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
@ 2024-08-30 9:51 ` Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 2/7] remoteproc: Add TEE support Arnaud Pouliquen
` (5 subsequent siblings)
6 siblings, 0 replies; 25+ messages in thread
From: Arnaud Pouliquen @ 2024-08-30 9:51 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
When a resource table is loaded by an external entity such as U-boot or
OP-TEE, we do not necessarily get the device address(da) but the physical
address(pa).
This helper performs similar translation than the rproc_da_to_va()
but based on a physical address.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
drivers/remoteproc/remoteproc_core.c | 46 ++++++++++++++++++++++++++++
include/linux/remoteproc.h | 1 +
2 files changed, 47 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index f276956f2c5c..ace11ea17097 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -230,6 +230,52 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
}
EXPORT_SYMBOL(rproc_da_to_va);
+/**
+ * rproc_pa_to_va() - lookup the kernel virtual address for a physical address of a remoteproc
+ * memory
+ *
+ * @rproc: handle of a remote processor
+ * @pa: remoteproc physical address
+ * @len: length of the memory region @pa is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
+ *
+ * This function is a helper function similar to rproc_da_to_va() but it deals with physical
+ * addresses instead of device addresses.
+ *
+ * Return: a valid kernel address on success or NULL on failure
+ */
+void *rproc_pa_to_va(struct rproc *rproc, phys_addr_t pa, size_t len, bool *is_iomem)
+{
+ struct rproc_mem_entry *carveout;
+ void *ptr = NULL;
+
+ list_for_each_entry(carveout, &rproc->carveouts, node) {
+ int offset = pa - carveout->dma;
+
+ /* Verify that carveout is allocated */
+ if (!carveout->va)
+ continue;
+
+ /* try next carveout if da is too small */
+ if (offset < 0)
+ continue;
+
+ /* try next carveout if da is too large */
+ if (offset + len > carveout->len)
+ continue;
+
+ ptr = carveout->va + offset;
+
+ if (is_iomem)
+ *is_iomem = carveout->is_iomem;
+
+ break;
+ }
+
+ return ptr;
+}
+EXPORT_SYMBOL(rproc_pa_to_va);
+
/**
* rproc_find_carveout_by_name() - lookup the carveout region by a name
* @rproc: handle of a remote processor
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index b4795698d8c2..8fd0d7f63c8e 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -690,6 +690,7 @@ int rproc_detach(struct rproc *rproc);
int rproc_set_firmware(struct rproc *rproc, const char *fw_name);
void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem);
+void *rproc_pa_to_va(struct rproc *rproc, phys_addr_t pa, size_t len, bool *is_iomem);
/* from remoteproc_coredump.c */
void rproc_coredump_cleanup(struct rproc *rproc);
--
2.25.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH v9 2/7] remoteproc: Add TEE support
2024-08-30 9:51 [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 1/7] remoteproc: core: Introduce rproc_pa_to_va helper Arnaud Pouliquen
@ 2024-08-30 9:51 ` Arnaud Pouliquen
2024-09-11 15:17 ` Mathieu Poirier
` (2 more replies)
2024-08-30 9:51 ` [PATCH v9 3/7] remoteproc: core: Refactor resource table cleanup into rproc_release_fw Arnaud Pouliquen
` (4 subsequent siblings)
6 siblings, 3 replies; 25+ messages in thread
From: Arnaud Pouliquen @ 2024-08-30 9:51 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
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 driver offers a client
interface to load a firmware by the secure part.
This firmware could be authenticated by the secure trusted application.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
Updates vs previous version:
- add TA_RPROC_CMD_RELEASE_FW TEE command support to release firmware resources,
- add tee_rproc_release_fw() API that will be called by the remoteproc core,
- release the firmware resources in case of error in tee_rproc_parse_fw() function
---
drivers/remoteproc/Kconfig | 10 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/remoteproc_tee.c | 486 ++++++++++++++++++++++++++++
include/linux/remoteproc.h | 4 +
include/linux/remoteproc_tee.h | 109 +++++++
5 files changed, 610 insertions(+)
create mode 100644 drivers/remoteproc/remoteproc_tee.c
create mode 100644 include/linux/remoteproc_tee.h
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index dda2ada215b7..93c3de7727bb 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -366,6 +366,16 @@ config XLNX_R5_REMOTEPROC
It's safe to say N if not interested in using RPU r5f cores.
+
+config REMOTEPROC_TEE
+ tristate "Remoteproc support by a TEE application"
+ 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..b4eb37177005 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_REMOTEPROC_TEE) += remoteproc_tee.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/remoteproc_tee.c b/drivers/remoteproc/remoteproc_tee.c
new file mode 100644
index 000000000000..d4a10c99f6e1
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_tee.c
@@ -0,0 +1,486 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) STMicroelectronics 2024
+ * 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/remoteproc_tee.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.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
+
+/*
+ * Release remote processor firmware images and associated resources.
+ * This command should be used in case an error occurs between the loading of
+ * the firmware images (A_RPROC_CMD_LOAD_FW) and the starting of the remote
+ * processor (TA_RPROC_CMD_START_FW) or after stopping the remote processor
+ * to release associated resources (TA_RPROC_CMD_STOP_FW).
+ *
+ * [in] params[0].value.a: Unique 32-bit remote processor identifier
+ */
+#define TA_RPROC_CMD_RELEASE_FW 6
+
+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_release_fw(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
+ struct tee_rproc *trproc = rproc->tee_interface;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ if (!trproc)
+ return -EINVAL;
+
+ tee_rproc_prepare_args(trproc, TA_RPROC_CMD_RELEASE_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_CMD_RELEASE_FW invoke failed TEE err: %x, ret:%x\n",
+ arg.ret, ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tee_rproc_release_fw);
+
+int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
+ struct tee_rproc *trproc = rproc->tee_interface;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_shm *fw_shm;
+ int ret;
+
+ 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);
+
+static int tee_rproc_get_loaded_rsc_table(struct rproc *rproc, phys_addr_t *rsc_pa,
+ size_t *table_sz)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
+ struct tee_rproc *trproc = rproc->tee_interface;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ 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 -EIO;
+ }
+
+ *table_sz = param[2].u.value.a;
+
+ if (*table_sz)
+ *rsc_pa = param[1].u.value.a;
+ else
+ *rsc_pa = 0;
+
+ return 0;
+}
+
+int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ phys_addr_t rsc_table;
+ void __iomem *rsc_va;
+ size_t table_sz;
+ int ret;
+
+ ret = tee_rproc_load_fw(rproc, fw);
+ if (ret)
+ return ret;
+
+ ret = tee_rproc_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
+ if (ret)
+ goto release_fw;
+
+ /*
+ * We assume here that the memory mapping is the same between the TEE and Linux kernel
+ * contexts. Else a new TEE remoteproc service could be needed to get a copy of the
+ * resource table
+ */
+ rsc_va = ioremap_wc(rsc_table, table_sz);
+ if (IS_ERR_OR_NULL(rsc_va)) {
+ dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %pa+%zx\n",
+ &rsc_table, table_sz);
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ /*
+ * Create a copy of the resource table to have the same behavior as the elf loader.
+ * This cached table will be used after the remoteproc stops to free resources, and for
+ * crash recovery to reapply the settings.
+ */
+ rproc->cached_table = kmemdup((__force void *)rsc_va, table_sz, GFP_KERNEL);
+ iounmap(rsc_va);
+
+ if (!rproc->cached_table) {
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ rproc->table_ptr = rproc->cached_table;
+ rproc->table_sz = table_sz;
+
+ return 0;
+
+release_fw:
+ tee_rproc_release_fw(rproc);
+ return ret;
+}
+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;
+ phys_addr_t rsc_table;
+ size_t table_sz;
+ int ret;
+
+ if (!trproc)
+ return NULL;
+
+ ret = tee_rproc_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
+ if (ret)
+ return NULL;
+
+ rproc->table_sz = table_sz;
+ if (!table_sz)
+ return NULL;
+
+ /*
+ * At this step the memory area that contains the resource table should have been registered
+ * by the remote proc platform driver and allocated by rproc_alloc_registered_carveouts().
+ */
+ return (struct resource_table *)rproc_pa_to_va(rproc, rsc_table, table_sz, NULL);
+}
+EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
+
+int tee_rproc_start(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
+ struct tee_rproc *trproc = rproc->tee_interface;
+ struct tee_ioctl_invoke_arg arg;
+ int ret = 0;
+
+ 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)
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tee_rproc_start);
+
+int tee_rproc_stop(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
+ struct tee_rproc *trproc = rproc->tee_interface;
+ struct tee_ioctl_invoke_arg arg;
+ 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;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tee_rproc_stop);
+
+static const struct tee_client_device_id 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_param param[MAX_TEE_PARAM_ARRY_MEMBER];
+ struct tee_ioctl_open_session_arg sess_arg;
+ struct tee_client_device *tee_device;
+ struct tee_rproc *trproc, *p_err;
+ 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);
+
+ /* Prevent tee rproc module from being removed */
+ if (!try_module_get(THIS_MODULE)) {
+ dev_err(tee_rproc_ctx->dev, "can't get owner\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ trproc = devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
+ if (!trproc) {
+ p_err = ERR_PTR(-ENOMEM);
+ goto module_put;
+ }
+ 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);
+ p_err = ERR_PTR(-EINVAL);
+ goto module_put;
+ }
+
+ 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;
+
+module_put:
+ module_put(THIS_MODULE);
+ return p_err;
+}
+EXPORT_SYMBOL_GPL(tee_rproc_register);
+
+int tee_rproc_unregister(struct tee_rproc *trproc)
+{
+ 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;
+
+ module_put(THIS_MODULE);
+
+ 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_rproc_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);
+ kfree(entry);
+ }
+
+ tee_client_close_context(tee_rproc_ctx->tee_ctx);
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(tee, tee_rproc_id_table);
+
+static struct tee_client_driver tee_rproc_fw_driver = {
+ .id_table = 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(" remote processor support with a TEE application");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 8fd0d7f63c8e..fbe1d6793709 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/remoteproc_tee.h b/include/linux/remoteproc_tee.h
new file mode 100644
index 000000000000..ab4d9b29c04b
--- /dev/null
+++ b/include/linux/remoteproc_tee.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright(c) 2024 STMicroelectronics
+ */
+
+#ifndef REMOTEPROC_TEE_H
+#define REMOTEPROC_TEE_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
+ */
+struct tee_rproc {
+ struct list_head node;
+ struct rproc *rproc;
+ struct device *parent;
+ u32 rproc_id;
+ u32 session_id;
+};
+
+#if IS_REACHABLE(CONFIG_REMOTEPROC_TEE)
+
+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);
+int tee_rproc_release_fw(struct rproc *rproc);
+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 int tee_rproc_release_fw(struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+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_REMOTEPROC_TEE */
+#endif /* REMOTEPROC_TEE_H */
--
2.25.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH v9 3/7] remoteproc: core: Refactor resource table cleanup into rproc_release_fw
2024-08-30 9:51 [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 1/7] remoteproc: core: Introduce rproc_pa_to_va helper Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 2/7] remoteproc: Add TEE support Arnaud Pouliquen
@ 2024-08-30 9:51 ` Arnaud Pouliquen
2024-09-11 15:20 ` Mathieu Poirier
2024-08-30 9:51 ` [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release Arnaud Pouliquen
` (3 subsequent siblings)
6 siblings, 1 reply; 25+ messages in thread
From: Arnaud Pouliquen @ 2024-08-30 9:51 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
This patch centralizing the cleanup of the resource table into a new
helper function rproc_release_fw().
Suggested-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
drivers/remoteproc/remoteproc_core.c | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index ace11ea17097..7694817f25d4 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1256,6 +1256,13 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
return 0;
}
+static void rproc_release_fw(struct rproc *rproc)
+{
+ /* Free the copy of the resource table */
+ kfree(rproc->cached_table);
+ rproc->cached_table = NULL;
+ rproc->table_ptr = NULL;
+}
/**
* rproc_resource_cleanup() - clean up and free all acquired resources
@@ -1485,9 +1492,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
clean_up_resources:
rproc_resource_cleanup(rproc);
- kfree(rproc->cached_table);
- rproc->cached_table = NULL;
- rproc->table_ptr = NULL;
+ rproc_release_fw(rproc);
unprepare_rproc:
/* release HW resources if needed */
rproc_unprepare_device(rproc);
@@ -2067,10 +2072,7 @@ int rproc_shutdown(struct rproc *rproc)
rproc_disable_iommu(rproc);
- /* Free the copy of the resource table */
- kfree(rproc->cached_table);
- rproc->cached_table = NULL;
- rproc->table_ptr = NULL;
+ rproc_release_fw(rproc);
out:
mutex_unlock(&rproc->lock);
return ret;
@@ -2133,10 +2135,7 @@ int rproc_detach(struct rproc *rproc)
rproc_disable_iommu(rproc);
- /* Free the copy of the resource table */
- kfree(rproc->cached_table);
- rproc->cached_table = NULL;
- rproc->table_ptr = NULL;
+ rproc_release_fw(rproc);
out:
mutex_unlock(&rproc->lock);
return ret;
--
2.25.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-08-30 9:51 [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
` (2 preceding siblings ...)
2024-08-30 9:51 ` [PATCH v9 3/7] remoteproc: core: Refactor resource table cleanup into rproc_release_fw Arnaud Pouliquen
@ 2024-08-30 9:51 ` Arnaud Pouliquen
2024-08-31 16:43 ` kernel test robot
` (4 more replies)
2024-08-30 9:51 ` [PATCH v9 5/7] dt-bindings: remoteproc: Add compatibility for TEE support Arnaud Pouliquen
` (2 subsequent siblings)
6 siblings, 5 replies; 25+ messages in thread
From: Arnaud Pouliquen @ 2024-08-30 9:51 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
Add support for releasing remote processor firmware through
the Trusted Execution Environment (TEE) interface.
The tee_rproc_release_fw() function is called in the following cases:
- An error occurs in rproc_start() between the loading of the segments and
the start of the remote processor.
- When rproc_release_fw is called on error or after stopping the remote
processor.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 7694817f25d4..32052dedc149 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -29,6 +29,7 @@
#include <linux/debugfs.h>
#include <linux/rculist.h>
#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
#include <linux/iommu.h>
#include <linux/idr.h>
#include <linux/elf.h>
@@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
static void rproc_release_fw(struct rproc *rproc)
{
+ if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
+ tee_rproc_release_fw(rproc);
+
/* Free the copy of the resource table */
kfree(rproc->cached_table);
rproc->cached_table = NULL;
@@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
if (ret) {
dev_err(dev, "failed to prepare subdevices for %s: %d\n",
rproc->name, ret);
- goto reset_table_ptr;
+ goto release_fw;
}
/* power up the remote processor */
@@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
rproc->ops->stop(rproc);
unprepare_subdevices:
rproc_unprepare_subdevices(rproc);
-reset_table_ptr:
+release_fw:
+ if (rproc->tee_interface)
+ tee_rproc_release_fw(rproc);
rproc->table_ptr = rproc->cached_table;
return ret;
--
2.25.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH v9 5/7] dt-bindings: remoteproc: Add compatibility for TEE support
2024-08-30 9:51 [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
` (3 preceding siblings ...)
2024-08-30 9:51 ` [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release Arnaud Pouliquen
@ 2024-08-30 9:51 ` Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 6/7] remoteproc: stm32: Create sub-functions to request shutdown and release Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 7/7] remoteproc: stm32: Add support of an OP-TEE TA to load the firmware Arnaud Pouliquen
6 siblings, 0 replies; 25+ messages in thread
From: Arnaud Pouliquen @ 2024-08-30 9:51 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
The "st,stm32mp1-m4-tee" compatible is utilized in a system configuration
where the Cortex-M4 firmware is loaded by the Trusted Execution Environment
(TEE).
For instance, this compatible is used in both the Linux and OP-TEE device
trees:
- In OP-TEE, a node is defined in the device tree with the
"st,stm32mp1-m4-tee" compatible to support signed remoteproc firmware.
Based on DT properties, the OP-TEE remoteproc framework is initiated to
expose a trusted application service to authenticate and load the remote
processor firmware provided by the Linux remoteproc framework, as well
as to start and stop the remote processor.
- In Linux, when the compatibility is set, the Cortex-M resets should not
be declared in the device tree. In such a configuration, the reset is
managed by the OP-TEE remoteproc driver and is no longer accessible from
the Linux kernel.
Associated with this new compatible, add the "st,proc-id" property to
identify the remote processor. This ID is used to define a unique ID,
common between Linux, U-Boot, and OP-TEE, to identify a coprocessor.
This ID will be used in requests to the OP-TEE remoteproc Trusted
Application to specify the remote processor.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
---
.../bindings/remoteproc/st,stm32-rproc.yaml | 58 ++++++++++++++++---
1 file changed, 50 insertions(+), 8 deletions(-)
diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml
index 370af61d8f28..409123cd4667 100644
--- a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml
@@ -16,7 +16,12 @@ maintainers:
properties:
compatible:
- const: st,stm32mp1-m4
+ enum:
+ - st,stm32mp1-m4
+ - st,stm32mp1-m4-tee
+ description:
+ Use "st,stm32mp1-m4" for the Cortex-M4 coprocessor management by non-secure context
+ Use "st,stm32mp1-m4-tee" for the Cortex-M4 coprocessor management by secure context
reg:
description:
@@ -43,6 +48,10 @@ properties:
- description: The offset of the hold boot setting register
- description: The field mask of the hold boot
+ st,proc-id:
+ description: remote processor identifier
+ $ref: /schemas/types.yaml#/definitions/uint32
+
st,syscfg-tz:
deprecated: true
description:
@@ -142,21 +151,43 @@ properties:
required:
- compatible
- reg
- - resets
allOf:
- if:
properties:
- reset-names:
- not:
- contains:
- const: hold_boot
+ compatible:
+ contains:
+ const: st,stm32mp1-m4
then:
+ if:
+ properties:
+ reset-names:
+ not:
+ contains:
+ const: hold_boot
+ then:
+ required:
+ - st,syscfg-holdboot
+ else:
+ properties:
+ st,syscfg-holdboot: false
+ required:
+ - reset-names
required:
- - st,syscfg-holdboot
- else:
+ - resets
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: st,stm32mp1-m4-tee
+ then:
properties:
st,syscfg-holdboot: false
+ reset-names: false
+ resets: false
+ required:
+ - st,proc-id
additionalProperties: false
@@ -188,5 +219,16 @@ examples:
st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>;
st,syscfg-m4-state = <&tamp 0x148 0xFFFFFFFF>;
};
+ - |
+ #include <dt-bindings/reset/stm32mp1-resets.h>
+ m4@10000000 {
+ compatible = "st,stm32mp1-m4-tee";
+ reg = <0x10000000 0x40000>,
+ <0x30000000 0x40000>,
+ <0x38000000 0x10000>;
+ st,proc-id = <0>;
+ st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>;
+ st,syscfg-m4-state = <&tamp 0x148 0xFFFFFFFF>;
+ };
...
--
2.25.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH v9 6/7] remoteproc: stm32: Create sub-functions to request shutdown and release
2024-08-30 9:51 [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
` (4 preceding siblings ...)
2024-08-30 9:51 ` [PATCH v9 5/7] dt-bindings: remoteproc: Add compatibility for TEE support Arnaud Pouliquen
@ 2024-08-30 9:51 ` Arnaud Pouliquen
2024-09-12 15:41 ` Mathieu Poirier
2024-08-30 9:51 ` [PATCH v9 7/7] remoteproc: stm32: Add support of an OP-TEE TA to load the firmware Arnaud Pouliquen
6 siblings, 1 reply; 25+ messages in thread
From: Arnaud Pouliquen @ 2024-08-30 9:51 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
To prepare for the support of TEE remoteproc, create sub-functions
that can be used in both cases, with and without remoteproc 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 8c7f7950b80e..79c638936163 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);
+ 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
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH v9 7/7] remoteproc: stm32: Add support of an OP-TEE TA to load the firmware
2024-08-30 9:51 [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
` (5 preceding siblings ...)
2024-08-30 9:51 ` [PATCH v9 6/7] remoteproc: stm32: Create sub-functions to request shutdown and release Arnaud Pouliquen
@ 2024-08-30 9:51 ` Arnaud Pouliquen
2024-09-13 16:03 ` Mathieu Poirier
6 siblings, 1 reply; 25+ messages in thread
From: Arnaud Pouliquen @ 2024-08-30 9:51 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
The new TEE remoteproc driver 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>
---
drivers/remoteproc/stm32_rproc.c | 63 ++++++++++++++++++++++++++++++--
1 file changed, 60 insertions(+), 3 deletions(-)
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 79c638936163..400a7a93b1c9 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -18,6 +18,7 @@
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@@ -257,6 +258,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 +707,20 @@ 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-tee" },
{},
};
MODULE_DEVICE_TABLE(of, stm32_rproc_match);
@@ -853,17 +879,42 @@ 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;
+ u32 proc_id;
int ret;
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
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.
+ */
+ ret = of_property_read_u32(np, "st,proc-id", &proc_id);
+ if (ret) {
+ dev_err(dev, "failed to read st,rproc-id property\n");
+ return ret;
+ }
+
+ rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
+ if (!rproc)
+ return -ENOMEM;
+
+ trproc = tee_rproc_register(dev, rproc, 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 +966,9 @@ static int stm32_rproc_probe(struct platform_device *pdev)
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
}
+ if (trproc)
+ tee_rproc_unregister(trproc);
+
return ret;
}
@@ -935,6 +989,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
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-08-30 9:51 ` [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release Arnaud Pouliquen
@ 2024-08-31 16:43 ` kernel test robot
2024-09-02 7:18 ` Arnaud POULIQUEN
2024-09-11 15:56 ` Mathieu Poirier
` (3 subsequent siblings)
4 siblings, 1 reply; 25+ messages in thread
From: kernel test robot @ 2024-08-31 16:43 UTC (permalink / raw)
To: Arnaud Pouliquen, Bjorn Andersson, Mathieu Poirier,
Jens Wiklander, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: oe-kbuild-all, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree, Arnaud Pouliquen
Hi Arnaud,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 5be63fc19fcaa4c236b307420483578a56986a37]
url: https://github.com/intel-lab-lkp/linux/commits/Arnaud-Pouliquen/remoteproc-core-Introduce-rproc_pa_to_va-helper/20240830-175609
base: 5be63fc19fcaa4c236b307420483578a56986a37
patch link: https://lore.kernel.org/r/20240830095147.3538047-5-arnaud.pouliquen%40foss.st.com
patch subject: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
config: loongarch-allmodconfig (https://download.01.org/0day-ci/archive/20240901/202409010034.Tln3soEY-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240901/202409010034.Tln3soEY-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202409010034.Tln3soEY-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/remoteproc/remoteproc_core.c:32:
>> include/linux/remoteproc_tee.h:52:12: warning: 'tee_rproc_parse_fw' defined but not used [-Wunused-function]
52 | static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
| ^~~~~~~~~~~~~~~~~~
vim +/tee_rproc_parse_fw +52 include/linux/remoteproc_tee.h
498143a453d14e Arnaud Pouliquen 2024-08-30 51
498143a453d14e Arnaud Pouliquen 2024-08-30 @52 static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
498143a453d14e Arnaud Pouliquen 2024-08-30 53 {
498143a453d14e Arnaud Pouliquen 2024-08-30 54 /* This shouldn't be possible */
498143a453d14e Arnaud Pouliquen 2024-08-30 55 WARN_ON(1);
498143a453d14e Arnaud Pouliquen 2024-08-30 56
498143a453d14e Arnaud Pouliquen 2024-08-30 57 return 0;
498143a453d14e Arnaud Pouliquen 2024-08-30 58 }
498143a453d14e Arnaud Pouliquen 2024-08-30 59
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-08-31 16:43 ` kernel test robot
@ 2024-09-02 7:18 ` Arnaud POULIQUEN
0 siblings, 0 replies; 25+ messages in thread
From: Arnaud POULIQUEN @ 2024-09-02 7:18 UTC (permalink / raw)
To: kernel test robot, Bjorn Andersson, Mathieu Poirier,
Jens Wiklander, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: oe-kbuild-all, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On 8/31/24 18:43, kernel test robot wrote:
> Hi Arnaud,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on 5be63fc19fcaa4c236b307420483578a56986a37]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Arnaud-Pouliquen/remoteproc-core-Introduce-rproc_pa_to_va-helper/20240830-175609
> base: 5be63fc19fcaa4c236b307420483578a56986a37
> patch link: https://lore.kernel.org/r/20240830095147.3538047-5-arnaud.pouliquen%40foss.st.com
> patch subject: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
> config: loongarch-allmodconfig (https://download.01.org/0day-ci/archive/20240901/202409010034.Tln3soEY-lkp@intel.com/config)
> compiler: loongarch64-linux-gcc (GCC) 14.1.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240901/202409010034.Tln3soEY-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202409010034.Tln3soEY-lkp@intel.com/
>
> All warnings (new ones prefixed by >>):
>
> In file included from drivers/remoteproc/remoteproc_core.c:32:
>>> include/linux/remoteproc_tee.h:52:12: warning: 'tee_rproc_parse_fw' defined but not used [-Wunused-function]
> 52 | static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> | ^~~~~~~~~~~~~~~~~~
>
>
> vim +/tee_rproc_parse_fw +52 include/linux/remoteproc_tee.h
>
> 498143a453d14e Arnaud Pouliquen 2024-08-30 51
> 498143a453d14e Arnaud Pouliquen 2024-08-30 @52 static int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> 498143a453d14e Arnaud Pouliquen 2024-08-30 53 {
> 498143a453d14e Arnaud Pouliquen 2024-08-30 54 /* This shouldn't be possible */
> 498143a453d14e Arnaud Pouliquen 2024-08-30 55 WARN_ON(1);
> 498143a453d14e Arnaud Pouliquen 2024-08-30 56
> 498143a453d14e Arnaud Pouliquen 2024-08-30 57 return 0;
> 498143a453d14e Arnaud Pouliquen 2024-08-30 58 }
> 498143a453d14e Arnaud Pouliquen 2024-08-30 59
>
The inline attribute is missing. As it is a minor fix, I'm waiting for more
reviews before fixing it in the next version.
Regards,
Arnaud
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 2/7] remoteproc: Add TEE support
2024-08-30 9:51 ` [PATCH v9 2/7] remoteproc: Add TEE support Arnaud Pouliquen
@ 2024-09-11 15:17 ` Mathieu Poirier
2024-09-11 15:25 ` Mathieu Poirier
2024-09-13 16:01 ` Mathieu Poirier
2 siblings, 0 replies; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-11 15:17 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:42AM +0200, 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 driver offers a client
> interface to load a firmware by the secure part.
> This firmware could be authenticated by the secure trusted application.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> Updates vs previous version:
> - add TA_RPROC_CMD_RELEASE_FW TEE command support to release firmware resources,
> - add tee_rproc_release_fw() API that will be called by the remoteproc core,
> - release the firmware resources in case of error in tee_rproc_parse_fw() function
> ---
> drivers/remoteproc/Kconfig | 10 +
> drivers/remoteproc/Makefile | 1 +
> drivers/remoteproc/remoteproc_tee.c | 486 ++++++++++++++++++++++++++++
> include/linux/remoteproc.h | 4 +
> include/linux/remoteproc_tee.h | 109 +++++++
> 5 files changed, 610 insertions(+)
> create mode 100644 drivers/remoteproc/remoteproc_tee.c
> create mode 100644 include/linux/remoteproc_tee.h
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index dda2ada215b7..93c3de7727bb 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -366,6 +366,16 @@ config XLNX_R5_REMOTEPROC
>
> It's safe to say N if not interested in using RPU r5f cores.
>
> +
> +config REMOTEPROC_TEE
> + tristate "Remoteproc support by a TEE application"
> + 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..b4eb37177005 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_REMOTEPROC_TEE) += remoteproc_tee.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/remoteproc_tee.c b/drivers/remoteproc/remoteproc_tee.c
> new file mode 100644
> index 000000000000..d4a10c99f6e1
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_tee.c
> @@ -0,0 +1,486 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) STMicroelectronics 2024
> + * 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/remoteproc_tee.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.h>
> +
> +#define MAX_TEE_PARAM_ARRY_MEMBER 4
s/MAX_TEE_PARAM_ARRY_MEMBER/MAX_TEE_PARAM_ARRAY_MEMBER
Comments for this patchset will be staggered over several days. I will let you
know when I am done.
> +
> +/*
> + * 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
> +
> +/*
> + * Release remote processor firmware images and associated resources.
> + * This command should be used in case an error occurs between the loading of
> + * the firmware images (A_RPROC_CMD_LOAD_FW) and the starting of the remote
> + * processor (TA_RPROC_CMD_START_FW) or after stopping the remote processor
> + * to release associated resources (TA_RPROC_CMD_STOP_FW).
> + *
> + * [in] params[0].value.a: Unique 32-bit remote processor identifier
> + */
> +#define TA_RPROC_CMD_RELEASE_FW 6
> +
> +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_release_fw(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret;
> +
> + if (!trproc)
> + return -EINVAL;
> +
> + tee_rproc_prepare_args(trproc, TA_RPROC_CMD_RELEASE_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_CMD_RELEASE_FW invoke failed TEE err: %x, ret:%x\n",
> + arg.ret, ret);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_release_fw);
> +
> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + struct tee_shm *fw_shm;
> + int ret;
> +
> + 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);
> +
> +static int tee_rproc_get_loaded_rsc_table(struct rproc *rproc, phys_addr_t *rsc_pa,
> + size_t *table_sz)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret;
> +
> + 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 -EIO;
> + }
> +
> + *table_sz = param[2].u.value.a;
> +
> + if (*table_sz)
> + *rsc_pa = param[1].u.value.a;
> + else
> + *rsc_pa = 0;
> +
> + return 0;
> +}
> +
> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> + phys_addr_t rsc_table;
> + void __iomem *rsc_va;
> + size_t table_sz;
> + int ret;
> +
> + ret = tee_rproc_load_fw(rproc, fw);
> + if (ret)
> + return ret;
> +
> + ret = tee_rproc_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
> + if (ret)
> + goto release_fw;
> +
> + /*
> + * We assume here that the memory mapping is the same between the TEE and Linux kernel
> + * contexts. Else a new TEE remoteproc service could be needed to get a copy of the
> + * resource table
> + */
> + rsc_va = ioremap_wc(rsc_table, table_sz);
> + if (IS_ERR_OR_NULL(rsc_va)) {
> + dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %pa+%zx\n",
> + &rsc_table, table_sz);
> + ret = -ENOMEM;
> + goto release_fw;
> + }
> +
> + /*
> + * Create a copy of the resource table to have the same behavior as the elf loader.
> + * This cached table will be used after the remoteproc stops to free resources, and for
> + * crash recovery to reapply the settings.
> + */
> + rproc->cached_table = kmemdup((__force void *)rsc_va, table_sz, GFP_KERNEL);
> + iounmap(rsc_va);
> +
> + if (!rproc->cached_table) {
> + ret = -ENOMEM;
> + goto release_fw;
> + }
> +
> + rproc->table_ptr = rproc->cached_table;
> + rproc->table_sz = table_sz;
> +
> + return 0;
> +
> +release_fw:
> + tee_rproc_release_fw(rproc);
> + return ret;
> +}
> +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;
> + phys_addr_t rsc_table;
> + size_t table_sz;
> + int ret;
> +
> + if (!trproc)
> + return NULL;
> +
> + ret = tee_rproc_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
> + if (ret)
> + return NULL;
> +
> + rproc->table_sz = table_sz;
> + if (!table_sz)
> + return NULL;
> +
> + /*
> + * At this step the memory area that contains the resource table should have been registered
> + * by the remote proc platform driver and allocated by rproc_alloc_registered_carveouts().
> + */
> + return (struct resource_table *)rproc_pa_to_va(rproc, rsc_table, table_sz, NULL);
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
> +
> +int tee_rproc_start(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret = 0;
> +
> + 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)
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_start);
> +
> +int tee_rproc_stop(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + 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;
> + }
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_stop);
> +
> +static const struct tee_client_device_id 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_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_ioctl_open_session_arg sess_arg;
> + struct tee_client_device *tee_device;
> + struct tee_rproc *trproc, *p_err;
> + 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);
> +
> + /* Prevent tee rproc module from being removed */
> + if (!try_module_get(THIS_MODULE)) {
> + dev_err(tee_rproc_ctx->dev, "can't get owner\n");
> + return ERR_PTR(-ENODEV);
> + }
> +
> + trproc = devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
> + if (!trproc) {
> + p_err = ERR_PTR(-ENOMEM);
> + goto module_put;
> + }
> + 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);
> + p_err = ERR_PTR(-EINVAL);
> + goto module_put;
> + }
> +
> + 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;
> +
> +module_put:
> + module_put(THIS_MODULE);
> + return p_err;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_register);
> +
> +int tee_rproc_unregister(struct tee_rproc *trproc)
> +{
> + 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;
> +
> + module_put(THIS_MODULE);
> +
> + 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_rproc_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);
> + kfree(entry);
> + }
> +
> + tee_client_close_context(tee_rproc_ctx->tee_ctx);
> +
> + return 0;
> +}
> +
> +MODULE_DEVICE_TABLE(tee, tee_rproc_id_table);
> +
> +static struct tee_client_driver tee_rproc_fw_driver = {
> + .id_table = 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(" remote processor support with a TEE application");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 8fd0d7f63c8e..fbe1d6793709 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/remoteproc_tee.h b/include/linux/remoteproc_tee.h
> new file mode 100644
> index 000000000000..ab4d9b29c04b
> --- /dev/null
> +++ b/include/linux/remoteproc_tee.h
> @@ -0,0 +1,109 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright(c) 2024 STMicroelectronics
> + */
> +
> +#ifndef REMOTEPROC_TEE_H
> +#define REMOTEPROC_TEE_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
> + */
> +struct tee_rproc {
> + struct list_head node;
> + struct rproc *rproc;
> + struct device *parent;
> + u32 rproc_id;
> + u32 session_id;
> +};
> +
> +#if IS_REACHABLE(CONFIG_REMOTEPROC_TEE)
> +
> +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);
> +int tee_rproc_release_fw(struct rproc *rproc);
> +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 int tee_rproc_release_fw(struct rproc *rproc)
> +{
> + /* This shouldn't be possible */
> + WARN_ON(1);
> +
> + return 0;
> +}
> +
> +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_REMOTEPROC_TEE */
> +#endif /* REMOTEPROC_TEE_H */
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 3/7] remoteproc: core: Refactor resource table cleanup into rproc_release_fw
2024-08-30 9:51 ` [PATCH v9 3/7] remoteproc: core: Refactor resource table cleanup into rproc_release_fw Arnaud Pouliquen
@ 2024-09-11 15:20 ` Mathieu Poirier
0 siblings, 0 replies; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-11 15:20 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:43AM +0200, Arnaud Pouliquen wrote:
> This patch centralizing the cleanup of the resource table into a new
> helper function rproc_release_fw().
>
Sure, but you did not explain _why_ the change is needed.
> Suggested-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> drivers/remoteproc/remoteproc_core.c | 21 ++++++++++-----------
> 1 file changed, 10 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index ace11ea17097..7694817f25d4 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -1256,6 +1256,13 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
> return 0;
> }
>
> +static void rproc_release_fw(struct rproc *rproc)
> +{
> + /* Free the copy of the resource table */
> + kfree(rproc->cached_table);
> + rproc->cached_table = NULL;
> + rproc->table_ptr = NULL;
> +}
>
> /**
> * rproc_resource_cleanup() - clean up and free all acquired resources
> @@ -1485,9 +1492,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
>
> clean_up_resources:
> rproc_resource_cleanup(rproc);
> - kfree(rproc->cached_table);
> - rproc->cached_table = NULL;
> - rproc->table_ptr = NULL;
> + rproc_release_fw(rproc);
> unprepare_rproc:
> /* release HW resources if needed */
> rproc_unprepare_device(rproc);
> @@ -2067,10 +2072,7 @@ int rproc_shutdown(struct rproc *rproc)
>
> rproc_disable_iommu(rproc);
>
> - /* Free the copy of the resource table */
> - kfree(rproc->cached_table);
> - rproc->cached_table = NULL;
> - rproc->table_ptr = NULL;
> + rproc_release_fw(rproc);
> out:
> mutex_unlock(&rproc->lock);
> return ret;
> @@ -2133,10 +2135,7 @@ int rproc_detach(struct rproc *rproc)
>
> rproc_disable_iommu(rproc);
>
> - /* Free the copy of the resource table */
> - kfree(rproc->cached_table);
> - rproc->cached_table = NULL;
> - rproc->table_ptr = NULL;
> + rproc_release_fw(rproc);
> out:
> mutex_unlock(&rproc->lock);
> return ret;
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 2/7] remoteproc: Add TEE support
2024-08-30 9:51 ` [PATCH v9 2/7] remoteproc: Add TEE support Arnaud Pouliquen
2024-09-11 15:17 ` Mathieu Poirier
@ 2024-09-11 15:25 ` Mathieu Poirier
2024-09-13 16:01 ` Mathieu Poirier
2 siblings, 0 replies; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-11 15:25 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:42AM +0200, 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 driver offers a client
> interface to load a firmware by the secure part.
> This firmware could be authenticated by the secure trusted application.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> Updates vs previous version:
> - add TA_RPROC_CMD_RELEASE_FW TEE command support to release firmware resources,
> - add tee_rproc_release_fw() API that will be called by the remoteproc core,
> - release the firmware resources in case of error in tee_rproc_parse_fw() function
> ---
> drivers/remoteproc/Kconfig | 10 +
> drivers/remoteproc/Makefile | 1 +
> drivers/remoteproc/remoteproc_tee.c | 486 ++++++++++++++++++++++++++++
> include/linux/remoteproc.h | 4 +
> include/linux/remoteproc_tee.h | 109 +++++++
> 5 files changed, 610 insertions(+)
> create mode 100644 drivers/remoteproc/remoteproc_tee.c
> create mode 100644 include/linux/remoteproc_tee.h
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index dda2ada215b7..93c3de7727bb 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -366,6 +366,16 @@ config XLNX_R5_REMOTEPROC
>
> It's safe to say N if not interested in using RPU r5f cores.
>
> +
> +config REMOTEPROC_TEE
> + tristate "Remoteproc support by a TEE application"
> + 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..b4eb37177005 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_REMOTEPROC_TEE) += remoteproc_tee.o
Please move this up to be with the other core remoteproc files, just after
CONFIG_REMOTEPROC_CDEV should be fine.
> 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/remoteproc_tee.c b/drivers/remoteproc/remoteproc_tee.c
> new file mode 100644
> index 000000000000..d4a10c99f6e1
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_tee.c
> @@ -0,0 +1,486 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) STMicroelectronics 2024
> + * 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/remoteproc_tee.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.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
> +
> +/*
> + * Release remote processor firmware images and associated resources.
> + * This command should be used in case an error occurs between the loading of
> + * the firmware images (A_RPROC_CMD_LOAD_FW) and the starting of the remote
> + * processor (TA_RPROC_CMD_START_FW) or after stopping the remote processor
> + * to release associated resources (TA_RPROC_CMD_STOP_FW).
> + *
> + * [in] params[0].value.a: Unique 32-bit remote processor identifier
> + */
> +#define TA_RPROC_CMD_RELEASE_FW 6
> +
> +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_release_fw(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret;
> +
> + if (!trproc)
> + return -EINVAL;
> +
> + tee_rproc_prepare_args(trproc, TA_RPROC_CMD_RELEASE_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_CMD_RELEASE_FW invoke failed TEE err: %x, ret:%x\n",
> + arg.ret, ret);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_release_fw);
> +
> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + struct tee_shm *fw_shm;
> + int ret;
> +
> + 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);
> +
> +static int tee_rproc_get_loaded_rsc_table(struct rproc *rproc, phys_addr_t *rsc_pa,
> + size_t *table_sz)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret;
> +
> + 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 -EIO;
> + }
> +
> + *table_sz = param[2].u.value.a;
> +
> + if (*table_sz)
> + *rsc_pa = param[1].u.value.a;
> + else
> + *rsc_pa = 0;
> +
> + return 0;
> +}
> +
> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> + phys_addr_t rsc_table;
> + void __iomem *rsc_va;
> + size_t table_sz;
> + int ret;
> +
> + ret = tee_rproc_load_fw(rproc, fw);
> + if (ret)
> + return ret;
> +
> + ret = tee_rproc_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
> + if (ret)
> + goto release_fw;
> +
> + /*
> + * We assume here that the memory mapping is the same between the TEE and Linux kernel
> + * contexts. Else a new TEE remoteproc service could be needed to get a copy of the
> + * resource table
> + */
> + rsc_va = ioremap_wc(rsc_table, table_sz);
> + if (IS_ERR_OR_NULL(rsc_va)) {
> + dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %pa+%zx\n",
> + &rsc_table, table_sz);
> + ret = -ENOMEM;
> + goto release_fw;
> + }
> +
> + /*
> + * Create a copy of the resource table to have the same behavior as the elf loader.
> + * This cached table will be used after the remoteproc stops to free resources, and for
> + * crash recovery to reapply the settings.
> + */
> + rproc->cached_table = kmemdup((__force void *)rsc_va, table_sz, GFP_KERNEL);
> + iounmap(rsc_va);
> +
> + if (!rproc->cached_table) {
> + ret = -ENOMEM;
> + goto release_fw;
> + }
> +
> + rproc->table_ptr = rproc->cached_table;
> + rproc->table_sz = table_sz;
> +
> + return 0;
> +
> +release_fw:
> + tee_rproc_release_fw(rproc);
> + return ret;
> +}
> +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;
> + phys_addr_t rsc_table;
> + size_t table_sz;
> + int ret;
> +
> + if (!trproc)
> + return NULL;
> +
> + ret = tee_rproc_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
> + if (ret)
> + return NULL;
> +
> + rproc->table_sz = table_sz;
> + if (!table_sz)
> + return NULL;
> +
> + /*
> + * At this step the memory area that contains the resource table should have been registered
> + * by the remote proc platform driver and allocated by rproc_alloc_registered_carveouts().
> + */
> + return (struct resource_table *)rproc_pa_to_va(rproc, rsc_table, table_sz, NULL);
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
> +
> +int tee_rproc_start(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret = 0;
> +
> + 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)
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_start);
> +
> +int tee_rproc_stop(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + 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;
> + }
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_stop);
> +
> +static const struct tee_client_device_id 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_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_ioctl_open_session_arg sess_arg;
> + struct tee_client_device *tee_device;
> + struct tee_rproc *trproc, *p_err;
> + 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);
> +
> + /* Prevent tee rproc module from being removed */
> + if (!try_module_get(THIS_MODULE)) {
> + dev_err(tee_rproc_ctx->dev, "can't get owner\n");
> + return ERR_PTR(-ENODEV);
> + }
> +
> + trproc = devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
> + if (!trproc) {
> + p_err = ERR_PTR(-ENOMEM);
> + goto module_put;
> + }
> + 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);
> + p_err = ERR_PTR(-EINVAL);
> + goto module_put;
> + }
> +
> + 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;
> +
> +module_put:
> + module_put(THIS_MODULE);
> + return p_err;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_register);
> +
> +int tee_rproc_unregister(struct tee_rproc *trproc)
> +{
> + 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;
> +
> + module_put(THIS_MODULE);
> +
> + 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_rproc_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);
> + kfree(entry);
> + }
> +
> + tee_client_close_context(tee_rproc_ctx->tee_ctx);
> +
> + return 0;
> +}
> +
> +MODULE_DEVICE_TABLE(tee, tee_rproc_id_table);
> +
> +static struct tee_client_driver tee_rproc_fw_driver = {
> + .id_table = 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(" remote processor support with a TEE application");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 8fd0d7f63c8e..fbe1d6793709 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/remoteproc_tee.h b/include/linux/remoteproc_tee.h
> new file mode 100644
> index 000000000000..ab4d9b29c04b
> --- /dev/null
> +++ b/include/linux/remoteproc_tee.h
> @@ -0,0 +1,109 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright(c) 2024 STMicroelectronics
> + */
> +
> +#ifndef REMOTEPROC_TEE_H
> +#define REMOTEPROC_TEE_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
> + */
> +struct tee_rproc {
> + struct list_head node;
> + struct rproc *rproc;
> + struct device *parent;
> + u32 rproc_id;
> + u32 session_id;
> +};
> +
> +#if IS_REACHABLE(CONFIG_REMOTEPROC_TEE)
> +
> +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);
> +int tee_rproc_release_fw(struct rproc *rproc);
> +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 int tee_rproc_release_fw(struct rproc *rproc)
> +{
> + /* This shouldn't be possible */
> + WARN_ON(1);
> +
> + return 0;
> +}
> +
> +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_REMOTEPROC_TEE */
> +#endif /* REMOTEPROC_TEE_H */
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-08-30 9:51 ` [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release Arnaud Pouliquen
2024-08-31 16:43 ` kernel test robot
@ 2024-09-11 15:56 ` Mathieu Poirier
2024-09-12 15:26 ` Mathieu Poirier
` (2 subsequent siblings)
4 siblings, 0 replies; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-11 15:56 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:44AM +0200, Arnaud Pouliquen wrote:
> Add support for releasing remote processor firmware through
> the Trusted Execution Environment (TEE) interface.
>
> The tee_rproc_release_fw() function is called in the following cases:
>
> - An error occurs in rproc_start() between the loading of the segments and
> the start of the remote processor.
> - When rproc_release_fw is called on error or after stopping the remote
> processor.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 7694817f25d4..32052dedc149 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -29,6 +29,7 @@
> #include <linux/debugfs.h>
> #include <linux/rculist.h>
> #include <linux/remoteproc.h>
> +#include <linux/remoteproc_tee.h>
> #include <linux/iommu.h>
> #include <linux/idr.h>
> #include <linux/elf.h>
> @@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
>
> static void rproc_release_fw(struct rproc *rproc)
> {
> + if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
> + tee_rproc_release_fw(rproc);
> +
If I understand correctly, the first condition is there because the
attach/detach scenario does not yet support management by the TEE. I would
simply move the check to tee_rproc_release_fw() with a comment to that effect.
> /* Free the copy of the resource table */
> kfree(rproc->cached_table);
> rproc->cached_table = NULL;
> @@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> if (ret) {
> dev_err(dev, "failed to prepare subdevices for %s: %d\n",
> rproc->name, ret);
> - goto reset_table_ptr;
> + goto release_fw;
> }
>
> /* power up the remote processor */
> @@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> rproc->ops->stop(rproc);
> unprepare_subdevices:
> rproc_unprepare_subdevices(rproc);
> -reset_table_ptr:
> +release_fw:
I would have kept the old label.
> + if (rproc->tee_interface)
> + tee_rproc_release_fw(rproc);
> rproc->table_ptr = rproc->cached_table;
>
> return ret;
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-08-30 9:51 ` [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release Arnaud Pouliquen
2024-08-31 16:43 ` kernel test robot
2024-09-11 15:56 ` Mathieu Poirier
@ 2024-09-12 15:26 ` Mathieu Poirier
2024-09-17 16:56 ` Arnaud POULIQUEN
2024-09-18 14:43 ` Arnaud POULIQUEN
2024-09-26 3:51 ` Bjorn Andersson
4 siblings, 1 reply; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-12 15:26 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:44AM +0200, Arnaud Pouliquen wrote:
> Add support for releasing remote processor firmware through
> the Trusted Execution Environment (TEE) interface.
>
> The tee_rproc_release_fw() function is called in the following cases:
>
> - An error occurs in rproc_start() between the loading of the segments and
> the start of the remote processor.
> - When rproc_release_fw is called on error or after stopping the remote
> processor.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 7694817f25d4..32052dedc149 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -29,6 +29,7 @@
> #include <linux/debugfs.h>
> #include <linux/rculist.h>
> #include <linux/remoteproc.h>
> +#include <linux/remoteproc_tee.h>
> #include <linux/iommu.h>
> #include <linux/idr.h>
> #include <linux/elf.h>
> @@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
>
> static void rproc_release_fw(struct rproc *rproc)
> {
> + if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
> + tee_rproc_release_fw(rproc);
Function tee_rproc_release_fw() returns a value that is ignored. I don't know
how it passes the Sparse checker but I already see patches coming in my Inbox to
deal with that. In this case there is nothing else to do if there is an error
releasing the firware. As such I would put a (void) in front and add a comment
about the return value being ignore on purpose.
> +
> /* Free the copy of the resource table */
> kfree(rproc->cached_table);
> rproc->cached_table = NULL;
> @@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> if (ret) {
> dev_err(dev, "failed to prepare subdevices for %s: %d\n",
> rproc->name, ret);
> - goto reset_table_ptr;
> + goto release_fw;
> }
>
> /* power up the remote processor */
> @@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> rproc->ops->stop(rproc);
> unprepare_subdevices:
> rproc_unprepare_subdevices(rproc);
> -reset_table_ptr:
> +release_fw:
> + if (rproc->tee_interface)
> + tee_rproc_release_fw(rproc);
Same here.
> rproc->table_ptr = rproc->cached_table;
>
> return ret;
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 6/7] remoteproc: stm32: Create sub-functions to request shutdown and release
2024-08-30 9:51 ` [PATCH v9 6/7] remoteproc: stm32: Create sub-functions to request shutdown and release Arnaud Pouliquen
@ 2024-09-12 15:41 ` Mathieu Poirier
0 siblings, 0 replies; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-12 15:41 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:46AM +0200, Arnaud Pouliquen wrote:
> To prepare for the support of TEE remoteproc, create sub-functions
> that can be used in both cases, with and without remoteproc 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 8c7f7950b80e..79c638936163 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);
When refactoring functions, please do not change the inner code. Here
@dummy_data was introduced. Making changes, even small ones, makes it really
hard to review your work. I'm pretty sure we talked about that before.
> + 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
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 2/7] remoteproc: Add TEE support
2024-08-30 9:51 ` [PATCH v9 2/7] remoteproc: Add TEE support Arnaud Pouliquen
2024-09-11 15:17 ` Mathieu Poirier
2024-09-11 15:25 ` Mathieu Poirier
@ 2024-09-13 16:01 ` Mathieu Poirier
2 siblings, 0 replies; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-13 16:01 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:42AM +0200, 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 driver offers a client
> interface to load a firmware by the secure part.
> This firmware could be authenticated by the secure trusted application.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> Updates vs previous version:
> - add TA_RPROC_CMD_RELEASE_FW TEE command support to release firmware resources,
> - add tee_rproc_release_fw() API that will be called by the remoteproc core,
> - release the firmware resources in case of error in tee_rproc_parse_fw() function
> ---
> drivers/remoteproc/Kconfig | 10 +
> drivers/remoteproc/Makefile | 1 +
> drivers/remoteproc/remoteproc_tee.c | 486 ++++++++++++++++++++++++++++
> include/linux/remoteproc.h | 4 +
> include/linux/remoteproc_tee.h | 109 +++++++
> 5 files changed, 610 insertions(+)
> create mode 100644 drivers/remoteproc/remoteproc_tee.c
> create mode 100644 include/linux/remoteproc_tee.h
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index dda2ada215b7..93c3de7727bb 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -366,6 +366,16 @@ config XLNX_R5_REMOTEPROC
>
> It's safe to say N if not interested in using RPU r5f cores.
>
> +
> +config REMOTEPROC_TEE
> + tristate "Remoteproc support by a TEE application"
> + 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..b4eb37177005 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_REMOTEPROC_TEE) += remoteproc_tee.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/remoteproc_tee.c b/drivers/remoteproc/remoteproc_tee.c
> new file mode 100644
> index 000000000000..d4a10c99f6e1
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_tee.c
> @@ -0,0 +1,486 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) STMicroelectronics 2024
> + * 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/remoteproc_tee.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.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
> +
> +/*
> + * Release remote processor firmware images and associated resources.
> + * This command should be used in case an error occurs between the loading of
> + * the firmware images (A_RPROC_CMD_LOAD_FW) and the starting of the remote
> + * processor (TA_RPROC_CMD_START_FW) or after stopping the remote processor
> + * to release associated resources (TA_RPROC_CMD_STOP_FW).
> + *
> + * [in] params[0].value.a: Unique 32-bit remote processor identifier
> + */
> +#define TA_RPROC_CMD_RELEASE_FW 6
> +
> +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_release_fw(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret;
> +
> + if (!trproc)
> + return -EINVAL;
> +
> + tee_rproc_prepare_args(trproc, TA_RPROC_CMD_RELEASE_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_CMD_RELEASE_FW invoke failed TEE err: %x, ret:%x\n",
> + arg.ret, ret);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_release_fw);
> +
> +int tee_rproc_load_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + struct tee_shm *fw_shm;
> + int ret;
> +
> + 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);
> +
> +static int tee_rproc_get_loaded_rsc_table(struct rproc *rproc, phys_addr_t *rsc_pa,
> + size_t *table_sz)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret;
A check to see if @trproc is valid is missing.
> +
> + 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 -EIO;
> + }
> +
> + *table_sz = param[2].u.value.a;
> +
> + if (*table_sz)
> + *rsc_pa = param[1].u.value.a;
> + else
> + *rsc_pa = 0;
> +
> + return 0;
> +}
> +
> +int tee_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> + phys_addr_t rsc_table;
> + void __iomem *rsc_va;
> + size_t table_sz;
> + int ret;
> +
> + ret = tee_rproc_load_fw(rproc, fw);
> + if (ret)
> + return ret;
> +
> + ret = tee_rproc_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
> + if (ret)
> + goto release_fw;
> +
> + /*
> + * We assume here that the memory mapping is the same between the TEE and Linux kernel
> + * contexts. Else a new TEE remoteproc service could be needed to get a copy of the
> + * resource table
> + */
> + rsc_va = ioremap_wc(rsc_table, table_sz);
> + if (IS_ERR_OR_NULL(rsc_va)) {
> + dev_err(tee_rproc_ctx->dev, "Unable to map memory region: %pa+%zx\n",
> + &rsc_table, table_sz);
> + ret = -ENOMEM;
> + goto release_fw;
> + }
> +
> + /*
> + * Create a copy of the resource table to have the same behavior as the elf loader.
> + * This cached table will be used after the remoteproc stops to free resources, and for
> + * crash recovery to reapply the settings.
> + */
Please indicate where ->cached_table is free'd.
> + rproc->cached_table = kmemdup((__force void *)rsc_va, table_sz, GFP_KERNEL);
> + iounmap(rsc_va);
> +
> + if (!rproc->cached_table) {
> + ret = -ENOMEM;
> + goto release_fw;
> + }
> +
> + rproc->table_ptr = rproc->cached_table;
> + rproc->table_sz = table_sz;
> +
> + return 0;
> +
> +release_fw:
> + tee_rproc_release_fw(rproc);
> + return ret;
> +}
> +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;
> + phys_addr_t rsc_table;
> + size_t table_sz;
> + int ret;
> +
> + if (!trproc)
> + return NULL;
> +
> + ret = tee_rproc_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
> + if (ret)
> + return NULL;
> +
> + rproc->table_sz = table_sz;
> + if (!table_sz)
> + return NULL;
> +
> + /*
> + * At this step the memory area that contains the resource table should have been registered
> + * by the remote proc platform driver and allocated by rproc_alloc_registered_carveouts().
> + */
> + return (struct resource_table *)rproc_pa_to_va(rproc, rsc_table, table_sz, NULL);
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_find_loaded_rsc_table);
> +
> +int tee_rproc_start(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + int ret = 0;
> +
> + 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)
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_start);
> +
> +int tee_rproc_stop(struct rproc *rproc)
> +{
> + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_rproc *trproc = rproc->tee_interface;
> + struct tee_ioctl_invoke_arg arg;
> + 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;
> + }
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_stop);
> +
> +static const struct tee_client_device_id 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_param param[MAX_TEE_PARAM_ARRY_MEMBER];
> + struct tee_ioctl_open_session_arg sess_arg;
> + struct tee_client_device *tee_device;
> + struct tee_rproc *trproc, *p_err;
> + 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);
> +
> + /* Prevent tee rproc module from being removed */
> + if (!try_module_get(THIS_MODULE)) {
> + dev_err(tee_rproc_ctx->dev, "can't get owner\n");
> + return ERR_PTR(-ENODEV);
> + }
> +
> + trproc = devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL);
> + if (!trproc) {
> + p_err = ERR_PTR(-ENOMEM);
> + goto module_put;
> + }
> + 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);
> + p_err = ERR_PTR(-EINVAL);
> + goto module_put;
> + }
> +
> + 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;
> +
> +module_put:
> + module_put(THIS_MODULE);
> + return p_err;
> +}
> +EXPORT_SYMBOL_GPL(tee_rproc_register);
> +
> +int tee_rproc_unregister(struct tee_rproc *trproc)
> +{
> + 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;
> +
> + module_put(THIS_MODULE);
> +
> + 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_rproc_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);
> + kfree(entry);
> + }
> +
> + tee_client_close_context(tee_rproc_ctx->tee_ctx);
> +
> + return 0;
> +}
> +
> +MODULE_DEVICE_TABLE(tee, tee_rproc_id_table);
> +
> +static struct tee_client_driver tee_rproc_fw_driver = {
> + .id_table = 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(" remote processor support with a TEE application");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 8fd0d7f63c8e..fbe1d6793709 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/remoteproc_tee.h b/include/linux/remoteproc_tee.h
> new file mode 100644
> index 000000000000..ab4d9b29c04b
> --- /dev/null
> +++ b/include/linux/remoteproc_tee.h
> @@ -0,0 +1,109 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright(c) 2024 STMicroelectronics
> + */
> +
> +#ifndef REMOTEPROC_TEE_H
> +#define REMOTEPROC_TEE_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
> + */
> +struct tee_rproc {
> + struct list_head node;
> + struct rproc *rproc;
> + struct device *parent;
> + u32 rproc_id;
> + u32 session_id;
> +};
> +
> +#if IS_REACHABLE(CONFIG_REMOTEPROC_TEE)
> +
> +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);
> +int tee_rproc_release_fw(struct rproc *rproc);
> +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 int tee_rproc_release_fw(struct rproc *rproc)
> +{
> + /* This shouldn't be possible */
> + WARN_ON(1);
> +
> + return 0;
> +}
> +
> +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_REMOTEPROC_TEE */
> +#endif /* REMOTEPROC_TEE_H */
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 7/7] remoteproc: stm32: Add support of an OP-TEE TA to load the firmware
2024-08-30 9:51 ` [PATCH v9 7/7] remoteproc: stm32: Add support of an OP-TEE TA to load the firmware Arnaud Pouliquen
@ 2024-09-13 16:03 ` Mathieu Poirier
2024-09-16 14:08 ` Arnaud POULIQUEN
0 siblings, 1 reply; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-13 16:03 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:47AM +0200, Arnaud Pouliquen wrote:
> The new TEE remoteproc driver 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>
> ---
> drivers/remoteproc/stm32_rproc.c | 63 ++++++++++++++++++++++++++++++--
> 1 file changed, 60 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
> index 79c638936163..400a7a93b1c9 100644
> --- a/drivers/remoteproc/stm32_rproc.c
> +++ b/drivers/remoteproc/stm32_rproc.c
> @@ -18,6 +18,7 @@
> #include <linux/pm_wakeirq.h>
> #include <linux/regmap.h>
> #include <linux/remoteproc.h>
> +#include <linux/remoteproc_tee.h>
> #include <linux/reset.h>
> #include <linux/slab.h>
> #include <linux/workqueue.h>
> @@ -257,6 +258,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 +707,20 @@ 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-tee" },
> {},
> };
> MODULE_DEVICE_TABLE(of, stm32_rproc_match);
> @@ -853,17 +879,42 @@ 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;
> + u32 proc_id;
> int ret;
>
> ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
> 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.
> + */
> + ret = of_property_read_u32(np, "st,proc-id", &proc_id);
> + if (ret) {
> + dev_err(dev, "failed to read st,rproc-id property\n");
> + return ret;
> + }
> +
> + rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
> + if (!rproc)
> + return -ENOMEM;
> +
> + trproc = tee_rproc_register(dev, rproc, 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 +966,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.
> + tee_rproc_unregister(trproc);
> +
> return ret;
> }
>
> @@ -935,6 +989,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
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 7/7] remoteproc: stm32: Add support of an OP-TEE TA to load the firmware
2024-09-13 16:03 ` Mathieu Poirier
@ 2024-09-16 14:08 ` Arnaud POULIQUEN
0 siblings, 0 replies; 25+ messages in thread
From: Arnaud POULIQUEN @ 2024-09-16 14:08 UTC (permalink / raw)
To: Mathieu Poirier
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
Hello Mathieu,
On 9/13/24 18:03, Mathieu Poirier wrote:
> On Fri, Aug 30, 2024 at 11:51:47AM +0200, Arnaud Pouliquen wrote:
>> The new TEE remoteproc driver 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>
>> ---
>> drivers/remoteproc/stm32_rproc.c | 63 ++++++++++++++++++++++++++++++--
>> 1 file changed, 60 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
>> index 79c638936163..400a7a93b1c9 100644
>> --- a/drivers/remoteproc/stm32_rproc.c
>> +++ b/drivers/remoteproc/stm32_rproc.c
>> @@ -18,6 +18,7 @@
>> #include <linux/pm_wakeirq.h>
>> #include <linux/regmap.h>
>> #include <linux/remoteproc.h>
>> +#include <linux/remoteproc_tee.h>
>> #include <linux/reset.h>
>> #include <linux/slab.h>
>> #include <linux/workqueue.h>
>> @@ -257,6 +258,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 +707,20 @@ 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-tee" },
>> {},
>> };
>> MODULE_DEVICE_TABLE(of, stm32_rproc_match);
>> @@ -853,17 +879,42 @@ 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;
>> + u32 proc_id;
>> int ret;
>>
>> ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
>> 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.
>> + */
>> + ret = of_property_read_u32(np, "st,proc-id", &proc_id);
>> + if (ret) {
>> + dev_err(dev, "failed to read st,rproc-id property\n");
>> + return ret;
>> + }
>> +
>> + rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, NULL, sizeof(*ddata));
>> + if (!rproc)
>> + return -ENOMEM;
>> +
>> + trproc = tee_rproc_register(dev, rproc, 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 +966,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 for the review, I will sent a V10 ASAP to fix this set.
Extra information: the OP-TEE that introduces the new
PTA_REMOTEPROC_RELEASE command has been merged.
Regards,
Arnaud
>
>> + tee_rproc_unregister(trproc);
>> +
>> return ret;
>> }
>>
>> @@ -935,6 +989,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
>>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-09-12 15:26 ` Mathieu Poirier
@ 2024-09-17 16:56 ` Arnaud POULIQUEN
2024-09-23 14:53 ` Mathieu Poirier
0 siblings, 1 reply; 25+ messages in thread
From: Arnaud POULIQUEN @ 2024-09-17 16:56 UTC (permalink / raw)
To: Mathieu Poirier
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
Hello Mathieu,
On 9/12/24 17:26, Mathieu Poirier wrote:
> On Fri, Aug 30, 2024 at 11:51:44AM +0200, Arnaud Pouliquen wrote:
>> Add support for releasing remote processor firmware through
>> the Trusted Execution Environment (TEE) interface.
>>
>> The tee_rproc_release_fw() function is called in the following cases:
>>
>> - An error occurs in rproc_start() between the loading of the segments and
>> the start of the remote processor.
>> - When rproc_release_fw is called on error or after stopping the remote
>> processor.
>>
>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>> ---
>> drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
>> 1 file changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
>> index 7694817f25d4..32052dedc149 100644
>> --- a/drivers/remoteproc/remoteproc_core.c
>> +++ b/drivers/remoteproc/remoteproc_core.c
>> @@ -29,6 +29,7 @@
>> #include <linux/debugfs.h>
>> #include <linux/rculist.h>
>> #include <linux/remoteproc.h>
>> +#include <linux/remoteproc_tee.h>
>> #include <linux/iommu.h>
>> #include <linux/idr.h>
>> #include <linux/elf.h>
>> @@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
>>
>> static void rproc_release_fw(struct rproc *rproc)
>> {
>> + if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
>> + tee_rproc_release_fw(rproc);
>
> Function tee_rproc_release_fw() returns a value that is ignored. I don't know
> how it passes the Sparse checker but I already see patches coming in my Inbox to
> deal with that. In this case there is nothing else to do if there is an error
> releasing the firware. As such I would put a (void) in front and add a comment
> about the return value being ignore on purpose.
Instead of ignoring the error, I wonder if we should panic in
tee_rproc_release_fw(). Indeed, we would be in an unexpected state without any
possible action to return to a normal state.
Regards,
Arnaud
>
>> +
>> /* Free the copy of the resource table */
>> kfree(rproc->cached_table);
>> rproc->cached_table = NULL;
>> @@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
>> if (ret) {
>> dev_err(dev, "failed to prepare subdevices for %s: %d\n",
>> rproc->name, ret);
>> - goto reset_table_ptr;
>> + goto release_fw;
>> }
>>
>> /* power up the remote processor */
>> @@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
>> rproc->ops->stop(rproc);
>> unprepare_subdevices:
>> rproc_unprepare_subdevices(rproc);
>> -reset_table_ptr:
>> +release_fw:
>> + if (rproc->tee_interface)
>> + tee_rproc_release_fw(rproc);
>
> Same here.
>
>> rproc->table_ptr = rproc->cached_table;
>>
>> return ret;
>> --
>> 2.25.1
>>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-08-30 9:51 ` [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release Arnaud Pouliquen
` (2 preceding siblings ...)
2024-09-12 15:26 ` Mathieu Poirier
@ 2024-09-18 14:43 ` Arnaud POULIQUEN
2024-09-23 15:13 ` Mathieu Poirier
2024-09-26 3:51 ` Bjorn Andersson
4 siblings, 1 reply; 25+ messages in thread
From: Arnaud POULIQUEN @ 2024-09-18 14:43 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree
Hello Mathieu,
On 8/30/24 11:51, Arnaud Pouliquen wrote:
> Add support for releasing remote processor firmware through
> the Trusted Execution Environment (TEE) interface.
>
> The tee_rproc_release_fw() function is called in the following cases:
>
> - An error occurs in rproc_start() between the loading of the segments and
> the start of the remote processor.
> - When rproc_release_fw is called on error or after stopping the remote
> processor.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 7694817f25d4..32052dedc149 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -29,6 +29,7 @@
> #include <linux/debugfs.h>
> #include <linux/rculist.h>
> #include <linux/remoteproc.h>
> +#include <linux/remoteproc_tee.h>
> #include <linux/iommu.h>
> #include <linux/idr.h>
> #include <linux/elf.h>
> @@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
>
> static void rproc_release_fw(struct rproc *rproc)
> {
> + if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
> + tee_rproc_release_fw(rproc);
I'm requesting you expertise to fix an issue I'm facing during my test preparing
the V10.
My issue is that here, we can call the tee_rproc_release_fw() function, defined
in remoteproc_tee built as a remoteproc_tee.ko module.
I tried to use the IS_ENABLED and IS_REACHABLE macros in remoteproc_tee.h, but
without success:
- use IS_ENABLED() results in a link error: "undefined reference to
tee_rproc_release_fw."
- use IS_REACHABLE() returns false and remoteproc_core calls the inline
tee_rproc_release_fw function that just call WARN_ON(1).
To solve the issue, I can see three alternatives:
1) Modify Kconfig and remoteproc_tee.c to support only built-in.
2) Use symbol_get/symbol_put.
3) Define a new rproc_ops->release_fw operation that will be initialized to
tee_rproc_release_fw.
From my perspective, the solution 3 seems to be the cleanest way, as it also
removes the dependency between remoteproc_core.c and remoteproc_tee.c. But
regarding previous discussion/series version, it seems that it could not be your
preferred solution.
Please, could you indicate your preference so that I can directly implement the
best solution (or perhaps you have another alternative to propose)?
Thanks in advance!
Arnaud
> +
> /* Free the copy of the resource table */
> kfree(rproc->cached_table);
> rproc->cached_table = NULL;
> @@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> if (ret) {
> dev_err(dev, "failed to prepare subdevices for %s: %d\n",
> rproc->name, ret);
> - goto reset_table_ptr;
> + goto release_fw;
> }
>
> /* power up the remote processor */
> @@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> rproc->ops->stop(rproc);
> unprepare_subdevices:
> rproc_unprepare_subdevices(rproc);
> -reset_table_ptr:
> +release_fw:
> + if (rproc->tee_interface)
> + tee_rproc_release_fw(rproc);
> rproc->table_ptr = rproc->cached_table;
>
> return ret;
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-09-17 16:56 ` Arnaud POULIQUEN
@ 2024-09-23 14:53 ` Mathieu Poirier
0 siblings, 0 replies; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-23 14:53 UTC (permalink / raw)
To: Arnaud POULIQUEN
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Tue, Sep 17, 2024 at 06:56:58PM +0200, Arnaud POULIQUEN wrote:
> Hello Mathieu,
>
> On 9/12/24 17:26, Mathieu Poirier wrote:
> > On Fri, Aug 30, 2024 at 11:51:44AM +0200, Arnaud Pouliquen wrote:
> >> Add support for releasing remote processor firmware through
> >> the Trusted Execution Environment (TEE) interface.
> >>
> >> The tee_rproc_release_fw() function is called in the following cases:
> >>
> >> - An error occurs in rproc_start() between the loading of the segments and
> >> the start of the remote processor.
> >> - When rproc_release_fw is called on error or after stopping the remote
> >> processor.
> >>
> >> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> >> ---
> >> drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
> >> 1 file changed, 8 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> >> index 7694817f25d4..32052dedc149 100644
> >> --- a/drivers/remoteproc/remoteproc_core.c
> >> +++ b/drivers/remoteproc/remoteproc_core.c
> >> @@ -29,6 +29,7 @@
> >> #include <linux/debugfs.h>
> >> #include <linux/rculist.h>
> >> #include <linux/remoteproc.h>
> >> +#include <linux/remoteproc_tee.h>
> >> #include <linux/iommu.h>
> >> #include <linux/idr.h>
> >> #include <linux/elf.h>
> >> @@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
> >>
> >> static void rproc_release_fw(struct rproc *rproc)
> >> {
> >> + if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
> >> + tee_rproc_release_fw(rproc);
> >
> > Function tee_rproc_release_fw() returns a value that is ignored. I don't know
> > how it passes the Sparse checker but I already see patches coming in my Inbox to
> > deal with that. In this case there is nothing else to do if there is an error
> > releasing the firware. As such I would put a (void) in front and add a comment
> > about the return value being ignore on purpose.
>
> Instead of ignoring the error, I wonder if we should panic in
> tee_rproc_release_fw(). Indeed, we would be in an unexpected state without any
> possible action to return to a normal state.
Nowadays a call to panic() is only used in very dire situations and I don't see
this meeting that requirement. I would just call a dev_err() and let it be.
>
> Regards,
> Arnaud
>
> >
> >> +
> >> /* Free the copy of the resource table */
> >> kfree(rproc->cached_table);
> >> rproc->cached_table = NULL;
> >> @@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> >> if (ret) {
> >> dev_err(dev, "failed to prepare subdevices for %s: %d\n",
> >> rproc->name, ret);
> >> - goto reset_table_ptr;
> >> + goto release_fw;
> >> }
> >>
> >> /* power up the remote processor */
> >> @@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> >> rproc->ops->stop(rproc);
> >> unprepare_subdevices:
> >> rproc_unprepare_subdevices(rproc);
> >> -reset_table_ptr:
> >> +release_fw:
> >> + if (rproc->tee_interface)
> >> + tee_rproc_release_fw(rproc);
> >
> > Same here.
> >
> >> rproc->table_ptr = rproc->cached_table;
> >>
> >> return ret;
> >> --
> >> 2.25.1
> >>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-09-18 14:43 ` Arnaud POULIQUEN
@ 2024-09-23 15:13 ` Mathieu Poirier
0 siblings, 0 replies; 25+ messages in thread
From: Mathieu Poirier @ 2024-09-23 15:13 UTC (permalink / raw)
To: Arnaud POULIQUEN
Cc: Bjorn Andersson, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Wed, Sep 18, 2024 at 04:43:32PM +0200, Arnaud POULIQUEN wrote:
> Hello Mathieu,
>
> On 8/30/24 11:51, Arnaud Pouliquen wrote:
> > Add support for releasing remote processor firmware through
> > the Trusted Execution Environment (TEE) interface.
> >
> > The tee_rproc_release_fw() function is called in the following cases:
> >
> > - An error occurs in rproc_start() between the loading of the segments and
> > the start of the remote processor.
> > - When rproc_release_fw is called on error or after stopping the remote
> > processor.
> >
> > Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> > ---
> > drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
> > 1 file changed, 8 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> > index 7694817f25d4..32052dedc149 100644
> > --- a/drivers/remoteproc/remoteproc_core.c
> > +++ b/drivers/remoteproc/remoteproc_core.c
> > @@ -29,6 +29,7 @@
> > #include <linux/debugfs.h>
> > #include <linux/rculist.h>
> > #include <linux/remoteproc.h>
> > +#include <linux/remoteproc_tee.h>
> > #include <linux/iommu.h>
> > #include <linux/idr.h>
> > #include <linux/elf.h>
> > @@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
> >
> > static void rproc_release_fw(struct rproc *rproc)
> > {
> > + if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
> > + tee_rproc_release_fw(rproc);
>
> I'm requesting you expertise to fix an issue I'm facing during my test preparing
> the V10.
>
> My issue is that here, we can call the tee_rproc_release_fw() function, defined
> in remoteproc_tee built as a remoteproc_tee.ko module.
>
> I tried to use the IS_ENABLED and IS_REACHABLE macros in remoteproc_tee.h, but
> without success:
> - use IS_ENABLED() results in a link error: "undefined reference to
> tee_rproc_release_fw."
> - use IS_REACHABLE() returns false and remoteproc_core calls the inline
> tee_rproc_release_fw function that just call WARN_ON(1).
>
> To solve the issue, I can see three alternatives:
>
> 1) Modify Kconfig and remoteproc_tee.c to support only built-in.
> 2) Use symbol_get/symbol_put.
> 3) Define a new rproc_ops->release_fw operation that will be initialized to
> tee_rproc_release_fw.
>
Option (1) is best but make sure people can disable the TEE interface if they
don't wish to use it.
> From my perspective, the solution 3 seems to be the cleanest way, as it also
> removes the dependency between remoteproc_core.c and remoteproc_tee.c. But
> regarding previous discussion/series version, it seems that it could not be your
> preferred solution.
>
> Please, could you indicate your preference so that I can directly implement the
> best solution (or perhaps you have another alternative to propose)?
>
> Thanks in advance!
>
> Arnaud
>
>
> > +
> > /* Free the copy of the resource table */
> > kfree(rproc->cached_table);
> > rproc->cached_table = NULL;
> > @@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> > if (ret) {
> > dev_err(dev, "failed to prepare subdevices for %s: %d\n",
> > rproc->name, ret);
> > - goto reset_table_ptr;
> > + goto release_fw;
> > }
> >
> > /* power up the remote processor */
> > @@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> > rproc->ops->stop(rproc);
> > unprepare_subdevices:
> > rproc_unprepare_subdevices(rproc);
> > -reset_table_ptr:
> > +release_fw:
> > + if (rproc->tee_interface)
> > + tee_rproc_release_fw(rproc);
> > rproc->table_ptr = rproc->cached_table;
> >
> > return ret;
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-08-30 9:51 ` [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release Arnaud Pouliquen
` (3 preceding siblings ...)
2024-09-18 14:43 ` Arnaud POULIQUEN
@ 2024-09-26 3:51 ` Bjorn Andersson
2024-09-27 10:01 ` Arnaud POULIQUEN
4 siblings, 1 reply; 25+ messages in thread
From: Bjorn Andersson @ 2024-09-26 3:51 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Mathieu Poirier, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
On Fri, Aug 30, 2024 at 11:51:44AM GMT, Arnaud Pouliquen wrote:
> Add support for releasing remote processor firmware through
> the Trusted Execution Environment (TEE) interface.
>
> The tee_rproc_release_fw() function is called in the following cases:
>
> - An error occurs in rproc_start() between the loading of the segments and
> the start of the remote processor.
> - When rproc_release_fw is called on error or after stopping the remote
> processor.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 7694817f25d4..32052dedc149 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -29,6 +29,7 @@
> #include <linux/debugfs.h>
> #include <linux/rculist.h>
> #include <linux/remoteproc.h>
> +#include <linux/remoteproc_tee.h>
> #include <linux/iommu.h>
> #include <linux/idr.h>
> #include <linux/elf.h>
> @@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
>
> static void rproc_release_fw(struct rproc *rproc)
> {
> + if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
> + tee_rproc_release_fw(rproc);
I don't like the idea of having op-tee specific calls made from the
core. If the problem is that we need to unroll something we did at load,
can we instead come up with a more generic mechanism to unload that? Or
can we perhaps postpone the tee interaction until start() to avoid the
gap?
PS. Most of the Qualcomm drivers are TEE-based...so the "tee_interface"
boolean check here is not very nice.
Regards,
Bjorn
> +
> /* Free the copy of the resource table */
> kfree(rproc->cached_table);
> rproc->cached_table = NULL;
> @@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> if (ret) {
> dev_err(dev, "failed to prepare subdevices for %s: %d\n",
> rproc->name, ret);
> - goto reset_table_ptr;
> + goto release_fw;
> }
>
> /* power up the remote processor */
> @@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
> rproc->ops->stop(rproc);
> unprepare_subdevices:
> rproc_unprepare_subdevices(rproc);
> -reset_table_ptr:
> +release_fw:
> + if (rproc->tee_interface)
> + tee_rproc_release_fw(rproc);
> rproc->table_ptr = rproc->cached_table;
>
> return ret;
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release
2024-09-26 3:51 ` Bjorn Andersson
@ 2024-09-27 10:01 ` Arnaud POULIQUEN
0 siblings, 0 replies; 25+ messages in thread
From: Arnaud POULIQUEN @ 2024-09-27 10:01 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Mathieu Poirier, Jens Wiklander, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-stm32, linux-arm-kernel, linux-remoteproc,
linux-kernel, op-tee, devicetree
Hello Bjorn,
On 9/26/24 05:51, Bjorn Andersson wrote:
> On Fri, Aug 30, 2024 at 11:51:44AM GMT, Arnaud Pouliquen wrote:
>> Add support for releasing remote processor firmware through
>> the Trusted Execution Environment (TEE) interface.
>>
>> The tee_rproc_release_fw() function is called in the following cases:
>>
>> - An error occurs in rproc_start() between the loading of the segments and
>> the start of the remote processor.
>> - When rproc_release_fw is called on error or after stopping the remote
>> processor.
>>
>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>> ---
>> drivers/remoteproc/remoteproc_core.c | 10 ++++++++--
>> 1 file changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
>> index 7694817f25d4..32052dedc149 100644
>> --- a/drivers/remoteproc/remoteproc_core.c
>> +++ b/drivers/remoteproc/remoteproc_core.c
>> @@ -29,6 +29,7 @@
>> #include <linux/debugfs.h>
>> #include <linux/rculist.h>
>> #include <linux/remoteproc.h>
>> +#include <linux/remoteproc_tee.h>
>> #include <linux/iommu.h>
>> #include <linux/idr.h>
>> #include <linux/elf.h>
>> @@ -1258,6 +1259,9 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
>>
>> static void rproc_release_fw(struct rproc *rproc)
>> {
>> + if (rproc->state == RPROC_OFFLINE && rproc->tee_interface)
>> + tee_rproc_release_fw(rproc);
>
> I don't like the idea of having op-tee specific calls made from the
> core. If the problem is that we need to unroll something we did at load,
> can we instead come up with a more generic mechanism to unload that? Or
As proposed in [1] an alternative could be to define a new rproc_ops->release_fw
operation that will be initialized to tee_rproc_release_fw in the platform driver.
> can we perhaps postpone the tee interaction until start() to avoid the
> gap?
In such a case, the management of the resource table should also be postponed
as the firmware has to be authenticated first.
The OP-TEE implementation authenticates the firmware during the load
(in-destination memory authentication), so the sequence is:
1) Load the firmware.
2) Get the resource table and initialize resources.
3) Start the firmware.
The tee_rproc_release_fw() is used if something goes wrong during step 2 an3.
From my perspective, this would result in an alternative boot sequence, as we
have today for "attach". I proposed this approach in my V3 [2]. But this add
complexity in remote proc core.
Please, could you align with Mathieu to define how we should move forward to
address your concerns?
[1]https://lkml.org/lkml/2024/9/18/612
[2]https://lore.kernel.org/lkml/8af59b01-53cf-4fc4-9946-6c630fb7b38e@quicinc.com/T/
Thanks and Regards,
Arnaud
>
>
> PS. Most of the Qualcomm drivers are TEE-based...so the "tee_interface"
> boolean check here is not very nice.
>
> Regards,
> Bjorn
>
>> +
>> /* Free the copy of the resource table */
>> kfree(rproc->cached_table);
>> rproc->cached_table = NULL;
>> @@ -1348,7 +1352,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
>> if (ret) {
>> dev_err(dev, "failed to prepare subdevices for %s: %d\n",
>> rproc->name, ret);
>> - goto reset_table_ptr;
>> + goto release_fw;
>> }
>>
>> /* power up the remote processor */
>> @@ -1376,7 +1380,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
>> rproc->ops->stop(rproc);
>> unprepare_subdevices:
>> rproc_unprepare_subdevices(rproc);
>> -reset_table_ptr:
>> +release_fw:
>> + if (rproc->tee_interface)
>> + tee_rproc_release_fw(rproc);
>> rproc->table_ptr = rproc->cached_table;
>>
>> return ret;
>> --
>> 2.25.1
>>
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2024-09-27 10:03 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-30 9:51 [PATCH v9 0/7] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 1/7] remoteproc: core: Introduce rproc_pa_to_va helper Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 2/7] remoteproc: Add TEE support Arnaud Pouliquen
2024-09-11 15:17 ` Mathieu Poirier
2024-09-11 15:25 ` Mathieu Poirier
2024-09-13 16:01 ` Mathieu Poirier
2024-08-30 9:51 ` [PATCH v9 3/7] remoteproc: core: Refactor resource table cleanup into rproc_release_fw Arnaud Pouliquen
2024-09-11 15:20 ` Mathieu Poirier
2024-08-30 9:51 ` [PATCH v9 4/7] remoteproc: core: Add TEE interface support for firmware release Arnaud Pouliquen
2024-08-31 16:43 ` kernel test robot
2024-09-02 7:18 ` Arnaud POULIQUEN
2024-09-11 15:56 ` Mathieu Poirier
2024-09-12 15:26 ` Mathieu Poirier
2024-09-17 16:56 ` Arnaud POULIQUEN
2024-09-23 14:53 ` Mathieu Poirier
2024-09-18 14:43 ` Arnaud POULIQUEN
2024-09-23 15:13 ` Mathieu Poirier
2024-09-26 3:51 ` Bjorn Andersson
2024-09-27 10:01 ` Arnaud POULIQUEN
2024-08-30 9:51 ` [PATCH v9 5/7] dt-bindings: remoteproc: Add compatibility for TEE support Arnaud Pouliquen
2024-08-30 9:51 ` [PATCH v9 6/7] remoteproc: stm32: Create sub-functions to request shutdown and release Arnaud Pouliquen
2024-09-12 15:41 ` Mathieu Poirier
2024-08-30 9:51 ` [PATCH v9 7/7] remoteproc: stm32: Add support of an OP-TEE TA to load the firmware Arnaud Pouliquen
2024-09-13 16:03 ` Mathieu Poirier
2024-09-16 14:08 ` Arnaud POULIQUEN
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).