ccmp15: add Cortex-M4 signed firmware support

Enable signed firmware to prevent unauthenticated code on the Cortex-M4
co-processor by verifying images against custom public key from OP-TEE.

https://onedigi.atlassian.net/browse/DEL-9920

Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
This commit is contained in:
Arturo Buzarra 2025-11-05 13:27:04 +01:00
parent 263d9a2baa
commit f99278db33
10 changed files with 428 additions and 0 deletions

View File

@ -0,0 +1,32 @@
From: Arturo Buzarra <arturo.buzarra@digi.com>
Date: Mon, 3 Nov 2025 23:00:27 +0100
Subject: [PATCH] ARM: dts: ccmp15: add signed firmware support for RPROC
Enable the Cortex-M4 inter-processor communication node so remoteproc can
load and authenticate signed firmware binaries.
https://onedigi.atlassian.net/browse/DEL-9920
Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
---
core/arch/arm/dts/ccmp15-dvk.dtsi | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/core/arch/arm/dts/ccmp15-dvk.dtsi b/core/arch/arm/dts/ccmp15-dvk.dtsi
index 7ea04b659..53533bd36 100644
--- a/core/arch/arm/dts/ccmp15-dvk.dtsi
+++ b/core/arch/arm/dts/ccmp15-dvk.dtsi
@@ -263,9 +263,12 @@
memory-region = <&retram>, <&mcusram1>, <&mcusram2>, <&mcusram3>;
mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>;
mbox-names = "vq0", "vq1", "shutdown", "detach";
+ resets = <&rcc MCU_R>, <&rcc MCU_HOLD_BOOT_R>;
+ reset-names = "mcu_rst", "hold_boot";
+ #reset-cells = <1>;
interrupt-parent = <&exti>;
interrupts = <68 1>;
- status = "disabled";
+ status = "okay";
};
&mcusram1 {

View File

@ -0,0 +1,55 @@
From: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
Date: Wed, 7 Jan 2026 14:10:13 +0100
Subject: [PATCH] Revert "drivers: remoteproc: stm32mp15: check Cortex-M
isolation"
This reverts commit b9f1c0820783436d45646fa50a62702f85d8fd62.
The MCKPROT is a system configuration that protects MCUSS clocks.
This must not be managed in remoteproc, as some peripherals use PLL3
as the parent clock.
Some SCMI services must first be implemented to manage the MCUSS clocks
before allowing the enabling of MCKPROT.
https://onedigi.atlassian.net/browse/DEL-9920
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
Change-Id: I78214e4c482c3947fa36c0bde7cd2fe2eee133d4
---
core/drivers/remoteproc/stm32_remoteproc.c | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/core/drivers/remoteproc/stm32_remoteproc.c b/core/drivers/remoteproc/stm32_remoteproc.c
index c99a47fe3..914474035 100644
--- a/core/drivers/remoteproc/stm32_remoteproc.c
+++ b/core/drivers/remoteproc/stm32_remoteproc.c
@@ -8,9 +8,6 @@
#include <drivers/firewall_device.h>
#include <drivers/rstctrl.h>
#include <drivers/stm32_remoteproc.h>
-#ifdef CFG_STM32MP15
-#include <drivers/stm32mp1_rcc.h>
-#endif
#include <keep.h>
#include <kernel/cache_helpers.h>
#include <kernel/dt_driver.h>
@@ -904,19 +901,6 @@ static TEE_Result stm32_rproc_probe(const void *fdt, int node,
stm32_rproc_a35ss_cfg(rproc);
#endif
-#ifdef CFG_STM32MP15
- if (!rproc->cdata->ns_loading) {
- if (!stm32_rcc_is_secure()) {
- if (IS_ENABLED(CFG_INSECURE))
- IMSG("WARNING: insecure rproc support regarding RCC hardening");
- else
- panic("RCC secure hardening issue");
- } else {
- stm32_rcc_set_mckprot(true);
- }
- }
-#endif
-
if (!rproc->cdata->ns_loading)
SLIST_INSERT_HEAD(&rproc_list, rproc, link);

View File

@ -0,0 +1,38 @@
From: Patrick Delaunay <patrick.delaunay@foss.st.com>
Date: Thu, 8 Jan 2026 10:20:20 +0100
Subject: [PATCH] drivers: firewall: stm32_etzpc: remove trace when rcc mckprot
is not activated
The RCC MCKPROT is deactivated even for remoteproc with secure loading
embedded in the platform, so stm32_rcc_is_mckprot always returns false
and a WARNING traces are displayed.
I/TC: WARNING: RCC tzen:1 mckprot:0, insecure ETZPC hardening
81:ETZPC_DECPROT_MCU_ISOLATION
This patch temporarily removes this trace in OpenSTLinux V6.X
as mckprot is not managed.
NOT_UPSTREAMABLE only avoid warning message.
https://onedigi.atlassian.net/browse/DEL-9920
Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Change-Id: If8cbec0bc2d5ad65b2f5e716c561f9598728d4e0
---
core/drivers/firewall/stm32_etzpc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/drivers/firewall/stm32_etzpc.c b/core/drivers/firewall/stm32_etzpc.c
index 257bcd76e..9d588b1c3 100644
--- a/core/drivers/firewall/stm32_etzpc.c
+++ b/core/drivers/firewall/stm32_etzpc.c
@@ -184,7 +184,7 @@ sanitize_decprot_config(uint32_t decprot_id __maybe_unused,
}
break;
case ETZPC_DECPROT_MCU_ISOLATION:
- if (!stm32_rcc_is_secure() || !stm32_rcc_is_mckprot()) {
+ if (!stm32_rcc_is_secure()) {
IMSG("WARNING: RCC tzen:%u mckprot:%u, insecure ETZPC hardening %"PRIu32":%s",
stm32_rcc_is_secure(), stm32_rcc_is_mckprot(),
decprot_id, etzpc_decprot_strings[attr]);

View File

@ -20,9 +20,17 @@ SRC_URI = " \
file://fonts.tar.gz;subdir=git;name=fonts \
"
SRC_URI:append:ccmp15 = " \
${@oe.utils.conditional('TRUSTFENCE_COPRO_ENABLED', '1' , 'file://0001-ARM-dts-ccmp15-add-signed-firmware-support-for-RPROC.patch \
file://0002-Revert-drivers-remoteproc-stm32mp15-check-Cortex-M-i.patch \
file://0003-drivers-firewall-stm32_etzpc-remove-trace-when-rcc-m.patch', '', d)} \
"
SRC_URI:append:ccmp25 = " \
${@oe.utils.conditional('TRUSTFENCE_COPRO_ENABLED', '1' , 'file://0001-ARM-dts-ccmp25-add-signed-firmware-support-for-RPROC.patch', '', d)} \
"
# Enable remoteproc OTP public key verification for signed firmware support
EXTRA_OEMAKE:append:ccmp25 = " ${@oe.utils.conditional('TRUSTFENCE_COPRO_ENABLED', '1', 'CFG_REMOTEPROC_PUB_KEY_VERIFY=y', '', d)}"
# Enable remoteproc custom public key verification for signed firmware support
EXTRA_OEMAKE:append:ccmp15 = " ${@oe.utils.conditional('TRUSTFENCE_COPRO_ENABLED', '1' , 'CFG_STM32MP_REMOTEPROC=y RPROC_SIGN_KEY=%s' % (d.getVar('TRUSTFENCE_COPRO_SIGN_KEY') or ''), '', d)}"

View File

@ -0,0 +1,30 @@
From: Arturo Buzarra <arturo.buzarra@digi.com>
Date: Tue, 4 Nov 2025 11:10:24 +0100
Subject: [PATCH] ARM: dts: ccmp15: add signed firmware support for RPROC
Declare only the shared memory used for inter-processor communication
(including the resource table) to allow remoteproc to load/authenticate signed
Cortex-M4 firmware.
https://onedigi.atlassian.net/browse/DEL-9920
Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
---
arch/arm/dts/ccmp15.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/dts/ccmp15.dtsi b/arch/arm/dts/ccmp15.dtsi
index 2e2e7788933..f0bdf3d6ed8 100644
--- a/arch/arm/dts/ccmp15.dtsi
+++ b/arch/arm/dts/ccmp15.dtsi
@@ -373,8 +373,8 @@
};
&m4_rproc {
- memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
- <&vdev0vring1>, <&vdev0buffer>, <&mcu_rsc_table>;
+ compatible = "st,stm32mp1-m4-tee";
+ memory-region = <&vdev0vring0>, <&vdev0vring1>, <&vdev0buffer>, <&mcu_rsc_table>;
mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
mbox-names = "vq0", "vq1", "shutdown";
interrupt-parent = <&exti>;

View File

@ -13,6 +13,10 @@ SRC_URI += " \
${@oe.utils.conditional('TRUSTFENCE_SIGN_FIT_STM', '1', 'file://fit_signature.cfg', '', d)} \
"
SRC_URI:append:ccmp15 = " \
${@oe.utils.conditional('TRUSTFENCE_COPRO_ENABLED', '1' , 'file://0001-ARM-dts-ccmp15-add-signed-firmware-support-for-RPROC.patch', '', d)} \
"
SRC_URI:append:ccmp25 = " \
${@oe.utils.conditional('TRUSTFENCE_COPRO_ENABLED', '1' , 'file://0001-ARM-dts-ccmp25-add-signed-firmware-support-for-RPROC.patch', '', d)} \
"

View File

@ -0,0 +1,38 @@
From: Arturo Buzarra <arturo.buzarra@digi.com>
Date: Tue, 4 Nov 2025 09:03:31 +0100
Subject: [PATCH] ARM: dts: ccmp15: add signed firmware support for RPROC
Declare only the shared memory used for inter-processor communication
(including the resource table) to allow remoteproc to load/authenticate signed
Cortex-M4 firmware.
https://onedigi.atlassian.net/browse/DEL-9920
Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
---
arch/arm/boot/dts/digi/ccmp15.dtsi | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/arm/boot/dts/digi/ccmp15.dtsi b/arch/arm/boot/dts/digi/ccmp15.dtsi
index 6f636dbf6ece..dd26d6d3d420 100644
--- a/arch/arm/boot/dts/digi/ccmp15.dtsi
+++ b/arch/arm/boot/dts/digi/ccmp15.dtsi
@@ -414,14 +414,13 @@ &ipcc {
};
&m4_rproc {
- memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
- <&vdev0vring1>, <&vdev0buffer>, <&mcu_rsc_table>;
+ compatible = "st,stm32mp1-m4-tee";
+ memory-region = <&vdev0vring0>, <&vdev0vring1>, <&vdev0buffer>, <&mcu_rsc_table>;
mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>;
mbox-names = "vq0", "vq1", "shutdown", "detach";
- resets = <&scmi_reset RST_SCMI_MCU>,
- <&scmi_reset RST_SCMI_MCU_HOLD_BOOT>;
- reset-names = "mcu_rst", "hold_boot";
/delete-property/ st,syscfg-holdboot;
+ /delete-property/ resets;
+ /delete-property/ reset-names;
interrupt-parent = <&exti>;
interrupts = <68 1>;
wakeup-source;

View File

@ -0,0 +1,217 @@
From: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
Date: Wed, 7 Jan 2026 14:56:36 +0100
Subject: [PATCH] remoteproc: stm32_rproc: make reset and hold boot optional
As specified in the bindings, the "mcu_rst" and "hold_boot" resets are
optional. They are needed only in the following topologies:
- stm32mp15: when the device tree defines the compatible "st,stm32mp1-m4"
- stm32mp2x A35 cold boot: when the device tree defines the compatible
"st,stm32mp2-m33"
This commit splits the management of the "mcu_rst" and "hold_boot" resets
per series:
- Migrates reset management code from stm32_rproc_parse_dt() to the
stm32_rproc_get_m4_reset() function
- Creates `stm32_rproc_get_m33_reset()` function to manage M33 resets
- No legacy property support needed
- "mcu_rst" and "hold_boot" are optional
Additionally, the get_reset() ops is called only for "st,stm32mp2-m33"
or "st,stm32mp2-m4" compatibles, when `ddata->trproc` is NULL.
https://onedigi.atlassian.net/browse/DEL-9920
Change-Id: Iddf5c28882eac4e051fec10367439f5991cdcaf1
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
drivers/remoteproc/stm32_rproc.c | 129 ++++++++++++++++++++-----------
1 file changed, 82 insertions(+), 47 deletions(-)
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index d21f22164814..46390045a63d 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -83,6 +83,7 @@ struct stm32_rproc_mem {
struct stm32_rproc_data {
int proc_id;
int (*get_info)(struct rproc *rproc);
+ int (*get_reset)(struct rproc *rproc);
};
struct stm32_mbox {
@@ -997,24 +998,6 @@ static int stm32_rproc_get_m33_info(struct rproc *rproc)
return 0;
}
-static const struct stm32_rproc_data stm32_rproc_stm32pm15 = {
- .proc_id = STM32_MP1_M4_PROC_ID,
- .get_info = stm32_rproc_get_m4_info,
-};
-
-static const struct stm32_rproc_data stm32_rproc_stm32pm25 = {
- .proc_id = STM32_MP2_M33_PROC_ID,
- .get_info = stm32_rproc_get_m33_info,
-};
-
-static const struct of_device_id stm32_rproc_match[] = {
- {.compatible = "st,stm32mp1-m4", .data = &stm32_rproc_stm32pm15},
- {.compatible = "st,stm32mp1-m4-tee", .data = &stm32_rproc_stm32pm15},
- {.compatible = "st,stm32mp2-m33", .data = &stm32_rproc_stm32pm25},
- {.compatible = "st,stm32mp2-m33-tee", .data = &stm32_rproc_stm32pm25},
- {},
-};
-MODULE_DEVICE_TABLE(of, stm32_rproc_match);
static int stm32_rproc_get_syscon(struct device_node *np, const char *prop,
struct stm32_syscon *syscon)
@@ -1038,42 +1021,29 @@ static int stm32_rproc_get_syscon(struct device_node *np, const char *prop,
return err;
}
-static int stm32_rproc_parse_dt(struct platform_device *pdev,
- struct stm32_rproc *ddata, bool *auto_boot)
+static int stm32_rproc_get_m4_reset(struct rproc *rproc)
{
- struct device *dev = &pdev->dev;
+ struct stm32_rproc *ddata = rproc->priv;
+ struct device *dev = rproc->dev.parent;
struct device_node *np = dev->of_node;
struct stm32_syscon tz;
unsigned int tzen;
- int err, irq;
-
- irq = platform_get_irq(pdev, 0);
- if (irq == -EPROBE_DEFER)
- return dev_err_probe(dev, irq, "failed to get interrupt\n");
-
- if (irq > 0) {
- err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
- dev_name(dev), pdev);
- if (err)
- return dev_err_probe(dev, err,
- "failed to request wdg irq\n");
-
- ddata->wdg_irq = irq;
-
- if (of_property_read_bool(np, "wakeup-source"))
- ddata->wdg_wake_up = 1;
-
- dev_info(dev, "wdg irq registered\n");
- }
+ int err = 0;
ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst");
if (!ddata->rst) {
/* Try legacy fallback method: get it by index */
ddata->rst = devm_reset_control_get_by_index(dev, 0);
}
- if (IS_ERR(ddata->rst))
- return dev_err_probe(dev, PTR_ERR(ddata->rst),
- "failed to get mcu_reset\n");
+ if (IS_ERR(ddata->rst)) {
+ if (PTR_ERR(ddata->rst) != -ENOENT)
+ return dev_err_probe(dev, PTR_ERR(ddata->rst),
+ "failed to get mcu_reset\n");
+ ddata->rst = NULL;
+ }
+
+ if (!ddata->rst)
+ return 0;
/*
* Three ways to manage the hold boot
@@ -1085,11 +1055,10 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
* - default(no SCMI, no SMC): the hold boot is managed as a syscon register
* The DT "reset-mames" property is optional, "st,syscfg-holdboot" is required
*/
-
ddata->hold_boot_rst = devm_reset_control_get_optional(dev, "hold_boot");
if (IS_ERR(ddata->hold_boot_rst))
return dev_err_probe(dev, PTR_ERR(ddata->hold_boot_rst),
- "failed to get hold_boot reset\n");
+ "failed to get hold_boot reset\n");
if (!ddata->hold_boot_rst && IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) {
/* Manage the MCU_BOOT using SMC call */
@@ -1108,6 +1077,72 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
/* Default: hold boot manage it through the syscon controller */
err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
&ddata->hold_boot);
+ }
+
+ return err;
+}
+
+static int stm32_rproc_get_m33_reset(struct rproc *rproc)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ struct device *dev = rproc->dev.parent;
+
+ ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst");
+ ddata->hold_boot_rst = devm_reset_control_get_optional(dev, "hold_boot");
+
+ return 0;
+}
+
+static const struct stm32_rproc_data stm32_rproc_stm32pm15 = {
+ .proc_id = STM32_MP1_M4_PROC_ID,
+ .get_info = stm32_rproc_get_m4_info,
+ .get_reset = stm32_rproc_get_m4_reset,
+};
+
+static const struct stm32_rproc_data stm32_rproc_stm32pm25 = {
+ .proc_id = STM32_MP2_M33_PROC_ID,
+ .get_info = stm32_rproc_get_m33_info,
+ .get_reset = stm32_rproc_get_m33_reset,
+};
+
+static const struct of_device_id stm32_rproc_match[] = {
+ {.compatible = "st,stm32mp1-m4", .data = &stm32_rproc_stm32pm15},
+ {.compatible = "st,stm32mp1-m4-tee", .data = &stm32_rproc_stm32pm15},
+ {.compatible = "st,stm32mp2-m33", .data = &stm32_rproc_stm32pm25},
+ {.compatible = "st,stm32mp2-m33-tee", .data = &stm32_rproc_stm32pm25},
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_rproc_match);
+
+static int stm32_rproc_parse_dt(struct platform_device *pdev,
+ struct rproc *rproc, bool *auto_boot)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct stm32_rproc *ddata = rproc->priv;
+ int err, irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq == -EPROBE_DEFER)
+ return dev_err_probe(dev, irq, "failed to get interrupt\n");
+
+ if (irq > 0) {
+ err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
+ dev_name(dev), pdev);
+ if (err)
+ return dev_err_probe(dev, err,
+ "failed to request wdg irq\n");
+
+ ddata->wdg_irq = irq;
+
+ if (of_property_read_bool(np, "wakeup-source"))
+ ddata->wdg_wake_up = 1;
+
+ dev_info(dev, "wdg irq registered\n");
+ }
+
+ if (!ddata->trproc) {
+ err = ddata->desc->get_reset(rproc);
if (err) {
dev_err(dev, "failed to get hold boot\n");
return err;
@@ -1231,7 +1266,7 @@ static int stm32_rproc_probe(struct platform_device *pdev)
ddata->desc = desc;
ddata->trproc = trproc;
- ret = stm32_rproc_parse_dt(pdev, ddata, &rproc->auto_boot);
+ ret = stm32_rproc_parse_dt(pdev, rproc, &rproc->auto_boot);
if (ret)
goto free_rproc;

View File

@ -22,6 +22,11 @@ SRC_URI:append = " \
${@bb.utils.contains('DISTRO_FEATURES', 'rt', '${RT_FILES}', '', d)} \
"
SRC_URI:append:ccmp15 = " \
${@oe.utils.conditional('TRUSTFENCE_COPRO_ENABLED', '1' , 'file://0001-ARM-dts-ccmp15-add-signed-firmware-support-for-RPROC.patch \
file://0002-remoteproc-stm32_rproc-make-reset-and-hold-boot-opti.patch', '', d)} \
"
SRC_URI:append:ccmp25 = " \
${@oe.utils.conditional('TRUSTFENCE_COPRO_ENABLED', '1' , 'file://0001-ARM64-dts-ccmp25-add-signed-firmware-support-for-RPR.patch', '', d)} \
"

View File

@ -199,6 +199,7 @@ python () {
if (d.getVar("DIGI_SOM") == "ccmp15" ):
d.setVar("SIGN_KEY", d.getVar("TRUSTFENCE_KEYS_PATH") + "/keys/privateKey.pem");
d.setVar("TRUSTFENCE_PASSWORD_FILE", d.getVar("TRUSTFENCE_KEYS_PATH") + "/keys/key_pass.txt")
d.setVar("TRUSTFENCE_COPRO_SIGN_KEY", d.getVar("TRUSTFENCE_KEYS_PATH") + "/rproc-keys/publicKey.pem")
else:
d.setVar("SIGN_KEY", d.getVar("TRUSTFENCE_KEYS_PATH") + "/keys/privateKey0%s.pem" % d.getVar("TRUSTFENCE_KEY_INDEX"));
d.setVar("TRUSTFENCE_PASSWORD_FILE", d.getVar("TRUSTFENCE_KEYS_PATH") + "/keys/key_pass0%s.txt" % d.getVar("TRUSTFENCE_KEY_INDEX"))