diff --git a/components/esp_system/port/soc/esp32/highint_hdl.S b/components/esp_system/port/soc/esp32/highint_hdl.S index 3ae31686d2..51b963cce6 100644 --- a/components/esp_system/port/soc/esp32/highint_hdl.S +++ b/components/esp_system/port/soc/esp32/highint_hdl.S @@ -173,7 +173,13 @@ xt_highintx: rsr a0, INTERRUPT extui a0, a0, ETS_IPC_ISR_INUM, 1 beqz a0, 1f - j esp_ipc_isr_handler + /* Jump to `esp_ipc_isr_handler` which is non-returning. We need to use `jx` + * because on Xtensa, `j` instruction can only refer to a label which + * is in the range [-131068;+131075]. If the destination is out of scope, + * linking will fail. So, to make sure we will always be able to jump to + * that subroutine, retrieve its address and store it in a register. */ + movi a0, esp_ipc_isr_handler + jx a0 1: #endif /* not CONFIG_FREERTOS_UNICORE */ diff --git a/components/esp_system/port/soc/esp32s3/highint_hdl.S b/components/esp_system/port/soc/esp32s3/highint_hdl.S index 91916e2cef..af0b2b31e7 100644 --- a/components/esp_system/port/soc/esp32s3/highint_hdl.S +++ b/components/esp_system/port/soc/esp32s3/highint_hdl.S @@ -49,7 +49,7 @@ xt_highint4: /* See if we're here for the IPC_ISR interrupt */ rsr a0, INTERRUPT extui a0, a0, ETS_IPC_ISR_INUM, 1 - bnez a0, esp_ipc_isr_handler + bnez a0, jump_to_esp_ipc_isr_handler #endif // not CONFIG_FREERTOS_UNICORE /* Allocate exception frame and save minimal context. */ @@ -130,6 +130,14 @@ xt_highint4: rsr a0, EXCSAVE_4 /* restore a0 */ rfi 4 +#ifdef CONFIG_ESP_IPC_ISR_ENABLE +jump_to_esp_ipc_isr_handler: + /* Address of `esp_ipc_isr_handler_address` will always be in `movi` range + * as it is defined right above. */ + movi a0, esp_ipc_isr_handler + jx a0 +#endif + /* The linker has no reason to link in this file; all symbols it exports are already defined (weakly!) in the default int handler. Define a symbol here so we can use it to have the linker inspect this anyway. */