diff --git a/arch/Kconfig b/arch/Kconfig index 94f88e36b8ef7..a6079eb90eef1 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -107,6 +107,7 @@ config RISCV select ARCH_IS_SET select HAS_DTS select ARCH_SUPPORTS_COREDUMP + select ARCH_HAS_CODE_DATA_RELOCATION select ARCH_HAS_THREAD_LOCAL_STORAGE select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD select USE_SWITCH_SUPPORTED @@ -577,6 +578,12 @@ config ARCH_HAS_SUSPEND_TO_RAM config ARCH_HAS_THREAD_ABORT bool +config ARCH_HAS_CODE_DATA_RELOCATION + bool + help + When selected, the architecture/SoC implements support for + CODE_DATA_RELOCATION in its linker scripts. + # # Hidden CPU family configs # @@ -755,6 +762,15 @@ config SRAM_REGION_PERMISSIONS paging, do not need memory protection, and would rather not use up RAM for the alignment between regions. +config CODE_DATA_RELOCATION + bool "Support code/data section relocation" + depends on ARCH_HAS_CODE_DATA_RELOCATION + help + Enable support for relocating .text, data and .bss sections from specified + files and placing them in a chosen memory region. Files to relocate and + the target regions should be specified in CMakeLists.txt using + zephyr_code_relocate(). + menu "Floating Point Options" config FPU diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 34339b9dce798..a6d1c7e9fb78f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -34,15 +34,6 @@ config ARM_CUSTOM_INTERRUPT_CONTROLLER family cores. The Cortex-M family cores are always equipped with the ARM Nested Vectored Interrupt Controller (NVIC). -config CODE_DATA_RELOCATION - bool "Relocate code/data sections" - depends on CPU_CORTEX_M || CPU_AARCH32_CORTEX_R - help - When selected this will relocate .text, data and .bss sections from - the specified files and places it in the required memory region. The - files should be specified in the CMakeList.txt file with - a cmake API zephyr_code_relocate(). - config CODE_DATA_RELOCATION_SRAM bool "Relocate code/data sections to SRAM" depends on CPU_CORTEX_M diff --git a/arch/arm/core/aarch32/Kconfig b/arch/arm/core/aarch32/Kconfig index 8d398a366c67b..aa71f567862fb 100644 --- a/arch/arm/core/aarch32/Kconfig +++ b/arch/arm/core/aarch32/Kconfig @@ -22,6 +22,7 @@ config CPU_CORTEX_M select ARCH_HAS_TIMING_FUNCTIONS if CPU_CORTEX_M_HAS_DWT select ARCH_SUPPORTS_ARCH_HW_INIT select ARCH_HAS_SUSPEND_TO_RAM + select ARCH_HAS_CODE_DATA_RELOCATION imply XIP help This option signifies the use of a CPU of the Cortex-M family. @@ -34,6 +35,7 @@ config CPU_AARCH32_CORTEX_R select HAS_FLASH_LOAD_OFFSET select ARCH_HAS_USERSPACE if ARM_MPU select ARCH_HAS_EXTRA_EXCEPTION_INFO + select ARCH_HAS_CODE_DATA_RELOCATION help This option signifies the use of a CPU of the Cortex-R family. diff --git a/cmake/linker/ld/target_relocation.cmake b/cmake/linker/ld/target_relocation.cmake index 60ff115efe285..b79c99c057f0a 100644 --- a/cmake/linker/ld/target_relocation.cmake +++ b/cmake/linker/ld/target_relocation.cmake @@ -9,6 +9,14 @@ macro(toolchain_ld_relocation) set(MEM_RELOCATION_SRAM_BSS_LD "${PROJECT_BINARY_DIR}/include/generated/linker_sram_bss_relocate.ld") set(MEM_RELOCATION_CODE "${PROJECT_BINARY_DIR}/code_relocation.c") + if(CONFIG_ARM) + set(MEM_REGION_DEFAULT_RAM SRAM) + elseif(CONFIG_RISCV) + set(MEM_REGION_DEFAULT_RAM RAM) + else() + # Name must be configured for newly-supported architectures + message(SEND_ERROR "Default RAM region name is unknown for target architecture") + endif() add_custom_command( OUTPUT ${MEM_RELOCATION_CODE} ${MEM_RELOCATION_LD} @@ -22,6 +30,7 @@ macro(toolchain_ld_relocation) -s ${MEM_RELOCATION_SRAM_DATA_LD} -b ${MEM_RELOCATION_SRAM_BSS_LD} -c ${MEM_RELOCATION_CODE} + --default_ram_region ${MEM_REGION_DEFAULT_RAM} DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} ) diff --git a/include/zephyr/arch/riscv/common/linker.ld b/include/zephyr/arch/riscv/common/linker.ld index 275464cf0695c..40d5607d1300b 100644 --- a/include/zephyr/arch/riscv/common/linker.ld +++ b/include/zephyr/arch/riscv/common/linker.ld @@ -125,6 +125,10 @@ SECTIONS #include } GROUP_LINK_IN(ROMABLE_REGION) +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + SECTION_PROLOGUE(_RESET_SECTION_NAME,,) { KEEP(*(.reset.*)) @@ -246,6 +250,11 @@ SECTIONS *(.bss) *(".bss.*") COMMON_SYMBOLS + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + /* * As memory is cleared in words only, it is simpler to ensure the BSS * section ends on a 4 byte boundary. This wastes a maximum of 3 bytes. @@ -287,6 +296,11 @@ SECTIONS * zephyr_linker_sources() Cmake function. */ #include + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + __data_end = .; } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index 064786b360948..48db0d6818116 100644 --- a/scripts/build/gen_relocate_app.py +++ b/scripts/build/gen_relocate_app.py @@ -41,8 +41,8 @@ import glob import warnings from elftools.elf.elffile import ELFFile +from elftools.elf.sections import SymbolTableSection -# This script will create linker commands for text,rodata data, bss section relocation PRINT_TEMPLATE = """ KEEP(*({0})) @@ -54,7 +54,7 @@ LOAD_ADDRESS_LOCATION_FLASH = """ #ifdef CONFIG_XIP -GROUP_DATA_LINK_IN({0}, FLASH) +GROUP_DATA_LINK_IN({0}, ROMABLE_REGION) #else GROUP_DATA_LINK_IN({0}, {0}) #endif @@ -153,6 +153,19 @@ """ +def region_is_default_ram(region_name: str) -> bool: + """ + Test whether a memory region with the given name is the system's default + RAM region or not. + + This is used to determine whether some items need to be omitted from + custom regions and instead be placed in the default. In particular, mutable + data placed in the default RAM section is ignored and is allowed to be + handled normally by the linker because it is placed in that region anyway. + """ + return region_name == args.default_ram_region + + def find_sections(filename, full_list_of_sections): with open(filename, 'rb') as obj_file_desc: full_lib = ELFFile(obj_file_desc) @@ -180,7 +193,7 @@ def find_sections(filename, full_list_of_sections): # common symbols and warns the user of the problem. # The solution to which is simply assigning a 0 to # bss variable and it will go to the required place. - if ".symtab" in section.name: + if isinstance(section, SymbolTableSection): symbols = [x for x in section.iter_symbols()] for symbol in symbols: if symbol.entry["st_shndx"] == 'SHN_COMMON': @@ -257,10 +270,10 @@ def string_create_helper(region, memory_type, # Create a complete list of funcs/ variables that goes in for this # memory type tmp = print_linker_sections(full_list_of_sections[region]) - if memory_type == 'SRAM' and region in {'data', 'bss'}: + if region_is_default_ram(memory_type) and region in {'data', 'bss'}: linker_string += tmp else: - if memory_type != 'SRAM' and region == 'rodata': + if not region_is_default_ram(memory_type) and region == 'rodata': align_size = 0 if memory_type in mpu_align: align_size = mpu_align[memory_type] @@ -268,7 +281,7 @@ def string_create_helper(region, memory_type, linker_string += LINKER_SECTION_SEQ_MPU.format(memory_type.lower(), region, memory_type.upper(), region.upper(), tmp, load_address_string, align_size) else: - if memory_type == 'SRAM' and region == 'text': + if region_is_default_ram(memory_type) and region == 'text': align_size = 0 linker_string += LINKER_SECTION_SEQ_MPU.format(memory_type.lower(), region, memory_type.upper(), region.upper(), tmp, load_address_string, align_size) @@ -292,16 +305,16 @@ def generate_linker_script(linker_file, sram_data_linker_file, sram_bss_linker_f is_copy = bool("|COPY" in memory_type) memory_type = memory_type.split("|", 1)[0] - if memory_type != "SRAM" and is_copy: + if region_is_default_ram(memory_type) and is_copy: gen_string += MPU_RO_REGION_START.format(memory_type.lower(), memory_type.upper()) gen_string += string_create_helper("text", memory_type, full_list_of_sections, 1, is_copy) gen_string += string_create_helper("rodata", memory_type, full_list_of_sections, 1, is_copy) - if memory_type != "SRAM" and is_copy: + if region_is_default_ram(memory_type) and is_copy: gen_string += MPU_RO_REGION_END.format(memory_type.lower()) - if memory_type == 'SRAM': + if region_is_default_ram(memory_type): gen_string_sram_data += string_create_helper("data", memory_type, full_list_of_sections, 1, 1) gen_string_sram_bss += string_create_helper("bss", memory_type, full_list_of_sections, 0, 1) else: @@ -336,7 +349,7 @@ def generate_memcpy_code(memory_type, full_list_of_sections, code_generation): # add all the regions that needs to be copied on boot up for mtype in ["text", "rodata", "data"]: - if memory_type == "SRAM" and mtype == "data": + if region_is_default_ram(memory_type) and mtype == "data": continue if full_list_of_sections[mtype] and generate_section[mtype]: @@ -345,7 +358,7 @@ def generate_memcpy_code(memory_type, full_list_of_sections, code_generation): memory_type.lower(), mtype) # add for all the bss data that needs to be zeroed on boot up - if full_list_of_sections["bss"] and generate_section["bss"] and memory_type != "SRAM": + if full_list_of_sections["bss"] and generate_section["bss"] and not region_is_default_ram(memory_type): code_generation["zero_code"] += MEMSET_TEMPLATE.format(memory_type.lower()) code_generation["extern"] += EXTERN_LINKER_VAR_DECLARATION.format( memory_type.lower(), "bss") @@ -390,6 +403,8 @@ def parse_args(): help="Output sram bss ld file") parser.add_argument("-c", "--output_code", required=False, help="Output relocation code header file") + parser.add_argument("-R", "--default_ram_region", default='SRAM', + help="Name of default RAM memory region for system") parser.add_argument("-v", "--verbose", action="count", default=0, help="Verbose Output") args = parser.parse_args() diff --git a/tests/application_development/code_relocation/CMakeLists.txt b/tests/application_development/code_relocation/CMakeLists.txt index d1811ae31652e..cc020d20db269 100644 --- a/tests/application_development/code_relocation/CMakeLists.txt +++ b/tests/application_development/code_relocation/CMakeLists.txt @@ -8,16 +8,22 @@ project(code_relocation) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) +if (CONFIG_ARM) + set(RAM_SECTION SRAM) +else() + set(RAM_SECTION RAM) +endif() + # Code relocation feature zephyr_code_relocate(src/test_file1.c SRAM2) -zephyr_code_relocate(src/test_file2.c SRAM) +zephyr_code_relocate(src/test_file2.c ${RAM_SECTION}) zephyr_code_relocate(src/test_file3.c SRAM2_TEXT) -zephyr_code_relocate(src/test_file3.c SRAM_DATA) +zephyr_code_relocate(src/test_file3.c ${RAM_SECTION}_DATA) zephyr_code_relocate(src/test_file3.c SRAM2_BSS) -zephyr_code_relocate(../../../kernel/sem.c SRAM) +zephyr_code_relocate(../../../kernel/sem.c ${RAM_SECTION}) if (CONFIG_RELOCATE_TO_ITCM) zephyr_code_relocate(../../../lib/libc/minimal/source/string/string.c ITCM_TEXT) diff --git a/tests/application_development/code_relocation/Kconfig b/tests/application_development/code_relocation/Kconfig index d40a9277aad93..21dbea3ff39ba 100644 --- a/tests/application_development/code_relocation/Kconfig +++ b/tests/application_development/code_relocation/Kconfig @@ -3,6 +3,5 @@ config RELOCATE_TO_ITCM bool "test with code relocate to itcm" - default y source "Kconfig.zephyr" diff --git a/tests/application_development/code_relocation/linker_riscv_qemu_sram2.ld b/tests/application_development/code_relocation/linker_riscv_qemu_sram2.ld new file mode 100644 index 0000000000000..57d3c733a2514 --- /dev/null +++ b/tests/application_development/code_relocation/linker_riscv_qemu_sram2.ld @@ -0,0 +1,34 @@ +/* + * Copyright 2022 The Chromium OS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the Cortex-M platforms. + */ + +#include +#include + +#include +#include + +/** enable CONFIG_SRAM2 or any other partition in soc Kconfig, + * this is just an example to show relocation of code/data/bss script + */ +#define _SRAM2_DATA_SECTION_NAME .sram2_data +#define _SRAM2_BSS_SECTION_NAME .sram2_bss +#define _SRAM2_TEXT_SECTION_NAME .sram2_text +#define SRAM2_ADDR (CONFIG_SRAM_BASE_ADDRESS + RAM_SIZE2) + +#define RAM_SIZE2 (CONFIG_SRAM_SIZE * 512) +MEMORY + { + SRAM2 (wx) : ORIGIN = (CONFIG_SRAM_BASE_ADDRESS + RAM_SIZE2), LENGTH = RAM_SIZE2 + } + +#include diff --git a/tests/application_development/code_relocation/prj_riscv.conf b/tests/application_development/code_relocation/prj_riscv.conf new file mode 100644 index 0000000000000..1bc4054f2d60c --- /dev/null +++ b/tests/application_development/code_relocation/prj_riscv.conf @@ -0,0 +1,5 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y +CONFIG_CUSTOM_LINKER_SCRIPT="linker_riscv_qemu_sram2.ld" diff --git a/tests/application_development/code_relocation/src/test_file1.c b/tests/application_development/code_relocation/src/test_file1.c index a8641fd4d478f..412b8decd84b2 100644 --- a/tests/application_development/code_relocation/src/test_file1.c +++ b/tests/application_development/code_relocation/src/test_file1.c @@ -8,28 +8,35 @@ #include #include -uint32_t var_sram2_data = 10U; -uint32_t var_sram2_bss; +/* + * These values will typically be placed in the appropriate sections, but may be moved around + * by the compiler; for instance var_sram2_data might end up in .rodata if the compiler can prove + * that it's never modified. To prevent that, we explicitly specify sections. + */ +__in_section(data, sram2, var) uint32_t var_sram2_data = 10U; +__in_section(bss, sram2, var) uint32_t var_sram2_bss; K_SEM_DEFINE(test, 0, 1); -const uint32_t var_sram2_rodata = 100U; +__in_section(rodata, sram2, var) const uint32_t var_sram2_rodata = 100U; __in_section(custom_section, static, var) uint32_t var_custom_data = 1U; extern void function_in_sram(int32_t value); void function_in_custom_section(void); +#define HAS_SRAM2_DATA_SECTION (CONFIG_ARM) + ZTEST(code_relocation, test_function_in_sram2) { - extern uint32_t __sram2_text_start; - extern uint32_t __sram2_text_end; - extern uint32_t __sram2_data_start; - extern uint32_t __sram2_data_end; - extern uint32_t __sram2_bss_start; - extern uint32_t __sram2_bss_end; - extern uint32_t __sram2_rodata_start; - extern uint32_t __sram2_rodata_end; - extern uint32_t __custom_section_start; - extern uint32_t __custom_section_end; + extern uintptr_t __sram2_text_start; + extern uintptr_t __sram2_text_end; + extern uintptr_t __sram2_data_start; + extern uintptr_t __sram2_data_end; + extern uintptr_t __sram2_bss_start; + extern uintptr_t __sram2_bss_end; + extern uintptr_t __sram2_rodata_start; + extern uintptr_t __sram2_rodata_end; + extern uintptr_t __custom_section_start; + extern uintptr_t __custom_section_end; /* Print values from sram2 */ printk("Address of var_sram2_data %p\n", &var_sram2_data); @@ -37,21 +44,21 @@ ZTEST(code_relocation, test_function_in_sram2) printk("Address of var_sram2_rodata %p\n", &var_sram2_rodata); printk("Address of var_sram2_bss %p\n\n", &var_sram2_bss); - zassert_between_inclusive((uint32_t)&var_sram2_data, - (uint32_t)&__sram2_data_start, - (uint32_t)&__sram2_data_end, + zassert_between_inclusive((uintptr_t)&var_sram2_data, + (uintptr_t)&__sram2_data_start, + (uintptr_t)&__sram2_data_end, "var_sram2_data not in sram2 region"); - zassert_between_inclusive((uint32_t)&k_sem_give, - (uint32_t)&__sram2_text_start, - (uint32_t)&__sram2_text_end, + zassert_between_inclusive((uintptr_t)&k_sem_give, + (uintptr_t)&__sram2_text_start, + (uintptr_t)&__sram2_text_end, "k_sem_give not in sram_text region"); - zassert_between_inclusive((uint32_t)&var_sram2_rodata, - (uint32_t)&__sram2_rodata_start, - (uint32_t)&__sram2_rodata_end, + zassert_between_inclusive((uintptr_t)&var_sram2_rodata, + (uintptr_t)&__sram2_rodata_start, + (uintptr_t)&__sram2_rodata_end, "var_sram2_rodata not in sram2_rodata region"); - zassert_between_inclusive((uint32_t)&var_sram2_bss, - (uint32_t)&__sram2_bss_start, - (uint32_t)&__sram2_bss_end, + zassert_between_inclusive((uintptr_t)&var_sram2_bss, + (uintptr_t)&__sram2_bss_start, + (uintptr_t)&__sram2_bss_end, "var_sram2_bss not in sram2_bss region"); /* Print values from sram */ @@ -62,13 +69,13 @@ ZTEST(code_relocation, test_function_in_sram2) &function_in_custom_section); printk("Address of custom_section data placed using attributes %p\n\n", &var_custom_data); - zassert_between_inclusive((uint32_t)&function_in_custom_section, - (uint32_t)&__custom_section_start, - (uint32_t)&__custom_section_end, + zassert_between_inclusive((uintptr_t)&function_in_custom_section, + (uintptr_t)&__custom_section_start, + (uintptr_t)&__custom_section_end, "function_in_custom_section not in custom_section region"); - zassert_between_inclusive((uint32_t)&var_custom_data, - (uint32_t)&__custom_section_start, - (uint32_t)&__custom_section_end, + zassert_between_inclusive((uintptr_t)&var_custom_data, + (uintptr_t)&__custom_section_start, + (uintptr_t)&__custom_section_end, "var_custom_data not in custom_section region"); k_sem_give(&test); diff --git a/tests/application_development/code_relocation/src/test_file3.c b/tests/application_development/code_relocation/src/test_file3.c index e7e141817da66..6499d86aae205 100644 --- a/tests/application_development/code_relocation/src/test_file3.c +++ b/tests/application_development/code_relocation/src/test_file3.c @@ -8,25 +8,25 @@ #include #include -uint32_t var_file3_sram_data = 10U; -uint32_t var_file3_sram2_bss; +__in_section(data, sram, var) uint32_t var_file3_sram_data = 10U; +__in_section(bss, sram2, var) uint32_t var_file3_sram2_bss; ZTEST(code_relocation, test_function_in_split_multiple) { - extern uint32_t __data_start; - extern uint32_t __data_end; - extern uint32_t __sram2_bss_start; - extern uint32_t __sram2_bss_end; + extern uintptr_t __data_start; + extern uintptr_t __data_end; + extern uintptr_t __sram2_bss_start; + extern uintptr_t __sram2_bss_end; printk("Address of var_file3_sram_data %p\n", &var_file3_sram_data); printk("Address of var_file3_sram2_bss %p\n\n", &var_file3_sram2_bss); - zassert_between_inclusive((uint32_t)&var_file3_sram_data, - (uint32_t)&__data_start, - (uint32_t)&__data_end, + zassert_between_inclusive((uintptr_t)&var_file3_sram_data, + (uintptr_t)&__data_start, + (uintptr_t)&__data_end, "var_file3_sram_data not in sram_data region"); - zassert_between_inclusive((uint32_t)&var_file3_sram2_bss, - (uint32_t)&__sram2_bss_start, - (uint32_t)&__sram2_bss_end, + zassert_between_inclusive((uintptr_t)&var_file3_sram2_bss, + (uintptr_t)&__sram2_bss_start, + (uintptr_t)&__sram2_bss_end, "var_file3_sram2_bss not in sram2_bss region"); } diff --git a/tests/application_development/code_relocation/testcase.yaml b/tests/application_development/code_relocation/testcase.yaml index 0118675872a2a..4c4563900522d 100644 --- a/tests/application_development/code_relocation/testcase.yaml +++ b/tests/application_development/code_relocation/testcase.yaml @@ -1,19 +1,22 @@ common: - arch_allow: arm tags: linker tests: tests.application_development.code_relocation: filter: not CONFIG_CPU_HAS_NXP_MPU and CONFIG_MINIMAL_LIBC and dt_chosen_enabled("zephyr,itcm") + arch_allow: arm extra_configs: - CONFIG_RELOCATE_TO_ITCM=y tests.application_development.code_relocation_kinetis: filter: CONFIG_CPU_HAS_NXP_MPU and CONFIG_MINIMAL_LIBC and dt_chosen_enabled("zephyr,itcm") + arch_allow: arm extra_configs: - CONFIG_RELOCATE_TO_ITCM=y - CONFIG_MPU_ALLOW_FLASH_WRITE=y tests.application_development.code_relocation.no_itcm: filter: not CONFIG_CPU_HAS_NXP_MPU and not dt_chosen_enabled("zephyr,itcm") - extra_configs: - - CONFIG_RELOCATE_TO_ITCM=n + arch_allow: arm extra_sections: _SRAM2_RODATA_SECTION_NAME _SRAM_TEXT_SECTION_NAME _SRAM_RODATA_SECTION_NAME _SRAM_DATA_SECTION_NAME _CUSTOM_SECTION_NAME2 platform_allow: qemu_cortex_m3 mps2_an385 sam_e70_xplained + tests.application_development.code_relocation.riscv: + extra_args: CONF_FILE="prj_riscv.conf" + platform_allow: qemu_riscv32 qemu_riscv64