On Fri, Mar 27, 2026 at 10:42:03AM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <[email protected]>
> 
> Cortex-M[7,33] processors use a fixed reset vector table format:
> 
>   0x00  Initial SP value
>   0x04  Reset vector
>   0x08  NMI
>   0x0C  ...
>   ...
>   IRQ[n]
> 
> In ELF images, the corresponding layout is:
> 
> reset_vectors:  --> hardware reset address
>         .word __stack_end__
>         .word Reset_Handler
>         .word NMI_Handler
>         .word HardFault_Handler
>         ...
>         .word UART_IRQHandler
>         .word SPI_IRQHandler
>         ...
> 
> Reset_Handler:  --> ELF entry point address
>         ...
> 
> The hardware fetches the first two words from reset_vectors and populates
> SP with __stack_end__ and PC with Reset_Handler. Execution proceeds from
> Reset_Handler.
> 
> However, the ELF entry point does not always match the hardware reset
> address. For example, on i.MX94 CM33S:
> 
>   ELF entry point:     0x0ffc211d
>   hardware reset base: 0x0ffc0000 (default reset value, sw programmable)
>

But why?  Why can't the ELF image be set to the right reset base?
 
> To derive the correct hardware reset address, the unused lower bits must
> be masked off. The boot code should apply a SoC-specific mask before
> programming the reset address registers, e.g.:
> 
>   reset_address = entry & reset_vector_mask
> 
> Current driver always programs the reset vector as 0. But i.MX94 CM33S's
> default reset base is 0x0ffc0000, so the correct reset vector must be
> passed to the SM API; otherwise the M33 Sync core cannot boot successfully.
> 
> rproc_elf_get_boot_addr() returns the ELF entry point, which is not the
> hardware reset vector address. To derive the proper reset vector, this
> patch introduces imx_rproc_get_boot_addr(), which masks the ELF entry
> point using the SoC‑specific 'reset_vector_mask'. The resulting reset
> vector address is then passed to the SM CPU/LMM reset vector API calls.
> 
> Signed-off-by: Peng Fan <[email protected]>
> ---
>  drivers/remoteproc/imx_rproc.c | 17 ++++++++++++++---
>  drivers/remoteproc/imx_rproc.h |  2 ++
>  2 files changed, 16 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 
> 0dd80e688b0ea3df4c66e5726884dc86c8a5a881..d8ead42640881bd523d605fa7002935ef6e98077
>  100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -345,7 +345,7 @@ static int imx_rproc_sm_cpu_start(struct rproc *rproc)
>       const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>       int ret;
>  
> -     ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false);
> +     ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, rproc->bootaddr, true, 
> false, false);
>       if (ret) {
>               dev_err(priv->dev, "Failed to set reset vector cpuid(%u): 
> %d\n", dcfg->cpuid, ret);
>               return ret;
> @@ -365,7 +365,7 @@ static int imx_rproc_sm_lmm_start(struct rproc *rproc)
>        * If the remoteproc core can't start the M7, it will already be
>        * handled in imx_rproc_sm_lmm_prepare().
>        */
> -     ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0);
> +     ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 
> rproc->bootaddr);
>       if (ret) {
>               dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): 
> %d\n",
>                       dcfg->lmid, dcfg->cpuid, ret);
> @@ -739,6 +739,17 @@ imx_rproc_elf_find_loaded_rsc_table(struct rproc *rproc, 
> const struct firmware *
>       return rproc_elf_find_loaded_rsc_table(rproc, fw);
>  }
>  
> +static u64 imx_rproc_get_boot_addr(struct rproc *rproc, const struct 
> firmware *fw)
> +{
> +     struct imx_rproc *priv = rproc->priv;
> +     u32 reset_vector_mask = GENMASK_U32(31, 0);
> +
> +     if (priv->dcfg->reset_vector_mask)
> +             reset_vector_mask = priv->dcfg->reset_vector_mask;
> +
> +     return rproc_elf_get_boot_addr(rproc, fw) & reset_vector_mask;
> +}
> +
>  static const struct rproc_ops imx_rproc_ops = {
>       .prepare        = imx_rproc_prepare,
>       .attach         = imx_rproc_attach,
> @@ -752,7 +763,7 @@ static const struct rproc_ops imx_rproc_ops = {
>       .find_loaded_rsc_table = imx_rproc_elf_find_loaded_rsc_table,
>       .get_loaded_rsc_table = imx_rproc_get_loaded_rsc_table,
>       .sanity_check   = rproc_elf_sanity_check,
> -     .get_boot_addr  = rproc_elf_get_boot_addr,
> +     .get_boot_addr  = imx_rproc_get_boot_addr,
>  };
>  
>  static int imx_rproc_addr_init(struct imx_rproc *priv,
> diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
> index 
> d37e6f90548cec727b4aeb874680b42af85bdbb4..0d7d48352a1091ad24e8e083172ce6da6d26ae10
>  100644
> --- a/drivers/remoteproc/imx_rproc.h
> +++ b/drivers/remoteproc/imx_rproc.h
> @@ -41,6 +41,8 @@ struct imx_rproc_dcfg {
>       /* For System Manager(SM) based SoCs */
>       u32                             cpuid; /* ID of the remote core */
>       u32                             lmid;  /* ID of the Logcial Machine */
> +     /* reset_vector = elf_entry_addr & reset_vector_mask */
> +     u32                             reset_vector_mask;
>  };
>  
>  #endif /* _IMX_RPROC_H */
> 
> -- 
> 2.37.1
> 

Reply via email to