On 2/23/24 19:37, Mathieu Poirier wrote: > On Fri, Feb 23, 2024 at 02:54:13PM +0100, Arnaud POULIQUEN wrote: >> Hello Mathieu, >> >> On 2/22/24 20:02, Mathieu Poirier wrote: >>> Hi, >>> >>> On Wed, Feb 14, 2024 at 06:21:27PM +0100, Arnaud Pouliquen wrote: >>>> The new TEE remoteproc device is used to manage remote firmware in a >>>> secure, trusted context. The 'st,stm32mp1-m4-tee' compatibility is >>>> introduced to delegate the loading of the firmware to the trusted >>>> execution context. In such cases, the firmware should be signed and >>>> adhere to the image format defined by the TEE. >>>> >>>> A new "to_attach" field is introduced to differentiate the use cases >>>> "firmware loaded by the boot stage" and "firmware loaded by the TEE". >>>> >>>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@xxxxxxxxxxx> >>>> --- >>>> V2 to V3 update: >>>> - remove stm32_rproc_tee_elf_sanity_check(), stm32_rproc_tee_elf_load() >>>> stm32_rproc_tee_elf_find_loaded_rsc_table() and stm32_rproc_tee_start() that are bnow unused >>>> - use new rproc::alt_boot field to sepcify that the alternate fboot method is used >>>> - use stm32_rproc::to_attach field to differenciate attch mode from remoteproc tee boot mode. >>>> - remove the used of stm32_rproc::fw_loaded >>>> --- >>>> drivers/remoteproc/stm32_rproc.c | 85 +++++++++++++++++++++++++++++--- >>>> 1 file changed, 79 insertions(+), 6 deletions(-) >>>> >>>> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c >>>> index fcc0001e2657..9cfcf66462e0 100644 >>>> --- a/drivers/remoteproc/stm32_rproc.c >>>> +++ b/drivers/remoteproc/stm32_rproc.c >>>> @@ -20,6 +20,7 @@ >>>> #include <linux/remoteproc.h> >>>> #include <linux/reset.h> >>>> #include <linux/slab.h> >>>> +#include <linux/tee_remoteproc.h> >>>> #include <linux/workqueue.h> >>>> >>>> #include "remoteproc_internal.h" >>>> @@ -49,6 +50,9 @@ >>>> #define M4_STATE_STANDBY 4 >>>> #define M4_STATE_CRASH 5 >>>> >>>> +/* Remote processor unique identifier aligned with the Trusted Execution Environment definitions */ >>>> +#define STM32_MP1_M4_PROC_ID 0 >>>> + >>>> struct stm32_syscon { >>>> struct regmap *map; >>>> u32 reg; >>>> @@ -90,6 +94,8 @@ struct stm32_rproc { >>>> struct stm32_mbox mb[MBOX_NB_MBX]; >>>> struct workqueue_struct *workqueue; >>>> bool hold_boot_smc; >>>> + bool to_attach; >>>> + struct tee_rproc *trproc; >>>> void __iomem *rsc_va; >>>> }; >>>> >>>> @@ -253,10 +259,30 @@ static int stm32_rproc_release(struct rproc *rproc) >>>> return err; >>>> } >>>> } >>>> + ddata->to_attach = false; >>>> >>>> return err; >>>> } >>>> >>>> +static int stm32_rproc_tee_attach(struct rproc *rproc) >>>> +{ >>>> + /* Nothing to do, remote proc already started by the secured context. */ >>>> + 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; >>>> @@ -637,10 +663,14 @@ stm32_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz) >>>> { >>>> struct stm32_rproc *ddata = rproc->priv; >>>> struct device *dev = rproc->dev.parent; >>>> + struct tee_rproc *trproc = ddata->trproc; >>>> phys_addr_t rsc_pa; >>>> u32 rsc_da; >>>> int err; >>>> >>>> + if (trproc && !ddata->to_attach) >>>> + return tee_rproc_get_loaded_rsc_table(rproc, table_sz); >>>> + >>> >>> Why do we need a flag at all? Why can't st_rproc_tee_ops::get_loaded_rsc_table >>> be set to tee_rproc_get_loaded_rsc_table()? >> >> >> This function is used to retrieve the address of the resource table in 3 cases >> - attach to a firmware started by the boot loader (U-boot). >> - load of the firmware by OP-TEE. >> - crash recovery on a signed firmware started by the boot loader. >> >> The flag is used to differentiate the attch from the other uses cases >> For instance we support this use case. >> 1) attach to the firmware on boot >> 2) crash during runtime >> 2a) stop the firmware by OP-TEE( ddata->to_attach set to 0) >> 2b) load the firmware by OP-TEE >> 2c) get the loaded resource table from OP-TEE (we can not guaranty >> that the firmware loaded on recovery is the same) >> 2d) restart the firmware by OP-TEE > > This is not maintainable and needs to be broken down into smaller > building blocks. The introduction of tee_rproc_parse_fw() should help dealing > with some of the complexity. The use cases I mentioned are supported by the legacy, if firmware is not authenticated by a Trusted Application. No problem to addressed this in a second step. I will remove this constrain from this series in next version. Regards, Arnaud > >> >>> >>>> /* The resource table has already been mapped, nothing to do */ >>>> if (ddata->rsc_va) >>>> goto done; >>>> @@ -693,8 +723,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, >>>> + .attach = stm32_rproc_tee_attach, >>>> + .kick = stm32_rproc_kick, >>>> + .get_loaded_rsc_table = stm32_rproc_get_loaded_rsc_table, >>>> + .find_loaded_rsc_table = tee_rproc_find_loaded_rsc_table, >>>> + .load = tee_rproc_load_fw, >>>> +}; >>>> + >>>> static const struct of_device_id stm32_rproc_match[] = { >>>> - { .compatible = "st,stm32mp1-m4" }, >>>> + {.compatible = "st,stm32mp1-m4",}, >>>> + {.compatible = "st,stm32mp1-m4-tee",}, >>>> {}, >>>> }; >>>> MODULE_DEVICE_TABLE(of, stm32_rproc_match); >>>> @@ -853,6 +895,7 @@ static int stm32_rproc_probe(struct platform_device *pdev) >>>> struct device *dev = &pdev->dev; >>>> struct stm32_rproc *ddata; >>>> struct device_node *np = dev->of_node; >>>> + struct tee_rproc *trproc = NULL; >>>> struct rproc *rproc; >>>> unsigned int state; >>>> int ret; >>>> @@ -861,12 +904,33 @@ static int stm32_rproc_probe(struct platform_device *pdev) >>>> if (ret) >>>> return ret; >>>> >>>> - rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); >>>> - if (!rproc) >>>> - return -ENOMEM; >>> >>> This patch doesn't apply to rproc-next - please rebase. >> >> Yes, sure. I forgot to mention in my cover letter that my series has been >> applied and tested on 841c35169323 (Linux 6.8-rc4). >> >>> >>> >>>> + 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. >>>> + */ >>>> + trproc = tee_rproc_register(dev, STM32_MP1_M4_PROC_ID); >>>> + if (IS_ERR(trproc)) { >>>> + dev_err_probe(dev, PTR_ERR(trproc), >>>> + "signed firmware not supported by TEE\n"); >>>> + return PTR_ERR(trproc); >>>> + } >>>> + } >>>> >>>> - ddata = rproc->priv; >>>> + rproc = rproc_alloc(dev, np->name, >>>> + trproc ? &st_rproc_tee_ops : &st_rproc_ops, >>>> + NULL, sizeof(*ddata)); >>>> + if (!rproc) { >>>> + ret = -ENOMEM; >>>> + goto free_tee; >>>> + } >>>> >>>> + ddata = rproc->priv; >>>> + ddata->trproc = trproc; >>> >>> My opinion hasn't changed from the previous patchet, i.e tee_rproc should be >>> folded in struct rproc as rproc::tee_interface. >> >> Sure, I will do it in next version >> >>> >>> More comments to come shortly... >>> >> >> Thanks! >> Arnaud >> >>>> + if (trproc) { >>>> + rproc->alt_boot = true; >>>> + trproc->rproc = rproc; >>>> + } >>>> rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); >>>> >>>> ret = stm32_rproc_parse_dt(pdev, ddata, &rproc->auto_boot); >>>> @@ -881,8 +945,10 @@ static int stm32_rproc_probe(struct platform_device *pdev) >>>> if (ret) >>>> goto free_rproc; >>>> >>>> - if (state == M4_STATE_CRUN) >>>> + if (state == M4_STATE_CRUN) { >>>> rproc->state = RPROC_DETACHED; >>>> + ddata->to_attach = true; >>>> + } >>>> >>>> rproc->has_iommu = false; >>>> ddata->workqueue = create_workqueue(dev_name(dev)); >>>> @@ -916,6 +982,10 @@ static int stm32_rproc_probe(struct platform_device *pdev) >>>> device_init_wakeup(dev, false); >>>> } >>>> rproc_free(rproc); >>>> +free_tee: >>>> + if (trproc) >>>> + tee_rproc_unregister(trproc); >>>> + >>>> return ret; >>>> } >>>> >>>> @@ -923,6 +993,7 @@ static void stm32_rproc_remove(struct platform_device *pdev) >>>> { >>>> struct rproc *rproc = platform_get_drvdata(pdev); >>>> struct stm32_rproc *ddata = rproc->priv; >>>> + struct tee_rproc *trproc = ddata->trproc; >>>> struct device *dev = &pdev->dev; >>>> >>>> if (atomic_read(&rproc->power) > 0) >>>> @@ -937,6 +1008,8 @@ static void stm32_rproc_remove(struct platform_device *pdev) >>>> device_init_wakeup(dev, false); >>>> } >>>> rproc_free(rproc); >>>> + if (trproc) >>>> + tee_rproc_unregister(trproc); >>>> } >>>> >>>> static int stm32_rproc_suspend(struct device *dev) >>>> -- >>>> 2.25.1 >>>> >>>