arch: arm: vector_table: Support vector table soft relay For SoCs that don't support vector table relocation in hardware, may not support bootloader like mcuboot. We introduce a way to relocate vector table in software by forwarding the control of incoming IRQs to a new vector table which address is save at fixed SRAM address. User can change the data in that fixed SRAM address in order to relocate vector table in software way. Signed-off-by: Ding Tao <miyatsu@qq.com>
diff --git a/arch/arm/core/CMakeLists.txt b/arch/arm/core/CMakeLists.txt index ae73f2b..d32114c 100644 --- a/arch/arm/core/CMakeLists.txt +++ b/arch/arm/core/CMakeLists.txt
@@ -15,6 +15,7 @@ zephyr_sources_ifdef(CONFIG_GEN_SW_ISR_TABLE isr_wrapper.S) zephyr_sources_ifdef(CONFIG_CPLUSPLUS __aeabi_atexit.c) zephyr_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c) +zephyr_sources_ifdef(CONFIG_CPU_CORTEX_M0 irq_relay.S) add_subdirectory_ifdef(CONFIG_CPU_CORTEX_M cortex_m) add_subdirectory_ifdef(CONFIG_CPU_HAS_MPU cortex_m/mpu)
diff --git a/arch/arm/core/cortex_m/prep_c.c b/arch/arm/core/cortex_m/prep_c.c index 5661b51..3348963 100644 --- a/arch/arm/core/cortex_m/prep_c.c +++ b/arch/arm/core/cortex_m/prep_c.c
@@ -26,6 +26,10 @@ #ifdef CONFIG_ARMV6_M +#if defined(CONFIG_SW_VECTOR_RELAY) +_GENERIC_SECTION(.vt_pointer_section) void *_vector_table_pointer; +#endif + #define VECTOR_ADDRESS 0 void __weak relocate_vector_table(void) { @@ -33,6 +37,8 @@ !defined(CONFIG_XIP) && (CONFIG_SRAM_BASE_ADDRESS != 0) size_t vector_size = (size_t)_vector_end - (size_t)_vector_start; memcpy(VECTOR_ADDRESS, _vector_start, vector_size); +#elif defined(CONFIG_SW_VECTOR_RELAY) + _vector_table_pointer = _vector_start; #endif }
diff --git a/arch/arm/core/irq_relay.S b/arch/arm/core/irq_relay.S new file mode 100644 index 0000000..fdaac71 --- /dev/null +++ b/arch/arm/core/irq_relay.S
@@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018 Ding Tao + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file irq_relay.S + * + * @brief IRQ relay vector table and relay handler for Cortex-M0 SoC + * + * In Cortex-M0, the vector table address can not be changed. Once the + * vector table is occupied by bootloader, there will be no IRQ support + * in chainloaded image. + * + * This program will link into bootloader, once an interrupt is coming, + * bootloader can forward the interrupt to the chainloaded image. This + * will support DFU on Cortex-M0 plantform. + * + * Note: Currently support mcuboot only. + * */ + +#include <board.h> +#include <toolchain.h> +#include <linker/sections.h> +#include <drivers/system_timer.h> + +_ASM_FILE_PROLOGUE + +#if defined(CONFIG_SW_VECTOR_RELAY) + +GDATA(_vector_table_pointer) +GDATA(_main_stack) + +SECTION_FUNC(vector_relay_handler, __vector_relay_handler) + mrs r0, ipsr; + lsls r0, r0, $0x02; + + ldr r1, = _vector_table_pointer; + ldr r1, [r1]; + adds r1, r1, r0; + ldr r1, [r1]; + + /** + * The size of IRQ vector is 4 bytes, the offset within vector table + * is the IRQ number times 4 (aka r0 << 2). As know as the r1 stored + * the offset of real vector table, thus the (r1 = r1 + r0 << 2) will + * be the real irq handle vector. + * */ + + bx r1; + +GTEXT(__vector_relay_handler) + +SECTION_FUNC(vector_relay_table, __vector_relay_table) + .word _main_stack + CONFIG_MAIN_STACK_SIZE + + .word __reset + + .word __vector_relay_handler /* nmi */ + .word __vector_relay_handler /* hard fault */ + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler /* svc */ + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler /* pendsv */ + .word __vector_relay_handler + /* End of system exception */ + + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + .word __vector_relay_handler + +#endif
diff --git a/include/arch/arm/cortex_m/scripts/linker.ld b/include/arch/arm/cortex_m/scripts/linker.ld index 171f0b3..87041e8 100644 --- a/include/arch/arm/cortex_m/scripts/linker.ld +++ b/include/arch/arm/cortex_m/scripts/linker.ld
@@ -95,6 +95,14 @@ KEEP(*(".dbghdr.*")) #endif . = CONFIG_TEXT_SECTION_OFFSET; + +#if defined(CONFIG_SW_VECTOR_RELAY) + KEEP(*(.vector_relay_table)) + KEEP(*(".vector_relay_table.*")) + KEEP(*(.vector_relay_handler)) + KEEP(*(".vector_relay_handler.*")) +#endif + _vector_start = .; KEEP(*(.exc_vector_table)) KEEP(*(".exc_vector_table.*")) @@ -184,6 +192,7 @@ GROUP_START(RAMABLE_REGION) + #if defined(CONFIG_SOC_SERIES_STM32F0X) && !defined(CONFIG_IS_BOOTLOADER) /* Must be first in ramable region */ SECTION_PROLOGUE(.st_stm32f0x_vt,(NOLOAD),) @@ -194,6 +203,15 @@ } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) #endif +#if defined(CONFIG_SW_VECTOR_RELAY) + /* Reserved 4 bytes to save vector table base address */ + SECTION_PROLOGUE(.vt_pointer,(NOLOAD),) + { + *(.vt_pointer_section) + *(".vt_pointer_section.*") + } +#endif + #ifdef CONFIG_APPLICATION_MEMORY SECTION_DATA_PROLOGUE(_APP_DATA_SECTION_NAME, (OPTIONAL),) {