diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index 5564d470324..9800a7ddee4 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -1261,14 +1261,22 @@ endfunction(zephyr_linker_sources) # Helper function for CONFIG_CODE_DATA_RELOCATION -# Call this function with 2 arguments file and then memory location +# Call this function with 2 arguments file and then memory location. +# One optional [NOCOPY] flag can be used. function(zephyr_code_relocate file location) + set(options NOCOPY) + cmake_parse_arguments(CODE_REL "${options}" "" "" ${ARGN}) if(NOT IS_ABSOLUTE ${file}) set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file}) endif() + if(NOT CODE_REL_NOCOPY) + set(copy_flag COPY) + else() + set(copy_flag NOCOPY) + endif() set_property(TARGET code_data_relocation_target APPEND PROPERTY COMPILE_DEFINITIONS - "${location}:${file}") + "${location}:${file}:${copy_flag}") endfunction() # Usage: diff --git a/doc/guides/code-relocation.rst b/doc/guides/code-relocation.rst index 63eed87f060..73874731fd4 100644 --- a/doc/guides/code-relocation.rst +++ b/doc/guides/code-relocation.rst @@ -91,6 +91,23 @@ This section shows additional configuration options that can be set in * Multiple regions can also be appended together such as: SRAM2_DATA_BSS. This will place data and bss inside SRAM2. +NOCOPY flag +=========== + +When a ``NOCOPY`` option is passed to the ``zephyr_code_relocate()`` function, +the relocation code is not generated in ``code_relocation.c``. This flag can be +used when we want to move the content of a specific file (or set of files) to a +XIP area. + +This example will place the .text section of the ``xip_external_flash.c`` file +to the ``EXTFLASH`` memory region where it will be executed from (XIP). The +.data will be relocated as usual into SRAM. + + .. code-block:: none + + zephyr_code_relocate(src/xip_external_flash.c EXTFLASH_TEXT NOCOPY) + zephyr_code_relocate(src/xip_external_flash.c SRAM_DATA) + Sample ====== A sample showcasing this feature is provided at @@ -100,3 +117,6 @@ This is an example of using the code relocation feature. This example will place .text, .data, .bss from 3 files to various parts in the SRAM using a custom linker file derived from ``include/arch/arm/aarch32/cortex_m/scripts/linker.ld`` + +A sample showcasing the NOCOPY flag is provided at +``$ZEPHYR_BASE/samples/application_development/code_relocation_nocopy/`` diff --git a/samples/application_development/code_relocation_nocopy/CMakeLists.txt b/samples/application_development/code_relocation_nocopy/CMakeLists.txt new file mode 100644 index 00000000000..5759dd1c9e3 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(code_relocation_nocopy) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +# Run ext_code from the external flash (XIP). No need to copy. +zephyr_code_relocate(src/ext_code.c EXTFLASH_TEXT NOCOPY) + +# But still relocate (copy) the data to SRAM +zephyr_code_relocate(src/ext_code.c SRAM_DATA) + +# sram_code instead runs entirely from SRAM after being copied there. +zephyr_code_relocate(src/sram_code.c SRAM) diff --git a/samples/application_development/code_relocation_nocopy/README.rst b/samples/application_development/code_relocation_nocopy/README.rst new file mode 100644 index 00000000000..1a55ca2bfe0 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/README.rst @@ -0,0 +1,13 @@ +.. _code_relocation_nocopy: + +Code relocation nocopy +###################### + +Overview +******** +A simple example that demonstrates how relocation of code, data or bss sections +using a custom linker script. + +Differently from the code relocation sample, this sample is relocating the +content of the ext_code.c file to a different FLASH section and the code is XIP +directly from there without the need to copy / relocate the code. diff --git a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld new file mode 100644 index 00000000000..8520525e119 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the Cortex-M platforms. + */ + +#include +#include +#include + +#include +#include + +/* + * Add another fake portion of FLASH to simulate a secondary or external FLASH + * that we can do XIP from. + */ +#define EXTFLASH_ADDR 0x5000 +#define EXTFLASH_SIZE (CONFIG_FLASH_SIZE * 1K - EXTFLASH_ADDR) + +MEMORY +{ + EXTFLASH (wx) : ORIGIN = 0x5000, LENGTH = EXTFLASH_SIZE +} + +#include diff --git a/samples/application_development/code_relocation_nocopy/prj.conf b/samples/application_development/code_relocation_nocopy/prj.conf new file mode 100644 index 00000000000..22d46057bee --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/prj.conf @@ -0,0 +1,5 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y +CONFIG_CUSTOM_LINKER_SCRIPT="linker_arm_nocopy.ld" +CONFIG_COVERAGE=n +CONFIG_XIP=y diff --git a/samples/application_development/code_relocation_nocopy/sample.yaml b/samples/application_development/code_relocation_nocopy/sample.yaml new file mode 100644 index 00000000000..e200c338525 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/sample.yaml @@ -0,0 +1,12 @@ +sample: + description: Code data relocation nocopy Sample + name: code relocation nocopy +tests: + sample.application_development.code_relocation_nocopy: + platform_allow: qemu_cortex_m3 + tags: linker + harness: console + harness_config: + type: one_line + regex: + - "Hello World! (.*)" diff --git a/samples/application_development/code_relocation_nocopy/src/ext_code.c b/samples/application_development/code_relocation_nocopy/src/ext_code.c new file mode 100644 index 00000000000..860050ecff6 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/src/ext_code.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +uint32_t var_ext_sram_data = 10U; + +void function_in_ext_flash(void) +{ + printk("Address of %s %p\n", __func__, &function_in_ext_flash); + printk("Address of var_ext_sram_data %p (%d)\n", &var_ext_sram_data, var_ext_sram_data); +} diff --git a/samples/application_development/code_relocation_nocopy/src/main.c b/samples/application_development/code_relocation_nocopy/src/main.c new file mode 100644 index 00000000000..8544e58e16b --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/src/main.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * Copyright (c) 2022 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* + * This function will allow execute from sram region. This is needed only for + * this sample because by default all soc will disable the execute from SRAM. + * An application that requires that the code be executed from SRAM will have + * to configure the region appropriately in arm_mpu_regions.c. + */ +#ifdef CONFIG_ARM_MPU +#include +void disable_mpu_rasr_xn(void) +{ + uint32_t index; + + /* + * Kept the max index as 8(irrespective of soc) because the sram would + * most likely be set at index 2. + */ + for (index = 0U; index < 8; index++) { + MPU->RNR = index; + if (MPU->RASR & MPU_RASR_XN_Msk) { + MPU->RASR ^= MPU_RASR_XN_Msk; + } + } +} +#endif /* CONFIG_ARM_MPU */ + +extern void function_in_ext_flash(void); +extern void function_in_sram(void); + +void main(void) +{ +#ifdef CONFIG_ARM_MPU + disable_mpu_rasr_xn(); +#endif /* CONFIG_ARM_MPU */ + + printk("Address of %s function %p\n", __func__, &main); + + function_in_ext_flash(); + function_in_sram(); + + printk("Hello World! %s\n", CONFIG_BOARD); +} diff --git a/samples/application_development/code_relocation_nocopy/src/sram_code.c b/samples/application_development/code_relocation_nocopy/src/sram_code.c new file mode 100644 index 00000000000..534da4b6113 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/src/sram_code.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +uint32_t var_sram_data = 10U; + +void function_in_sram(void) +{ + printk("Address of %s %p\n", __func__, &function_in_sram); + printk("Address of var_sram_data %p (%d)\n", &var_sram_data, var_sram_data); +} diff --git a/scripts/gen_relocate_app.py b/scripts/gen_relocate_app.py index 1c5a0e1d2c0..90424cd1988 100644 --- a/scripts/gen_relocate_app.py +++ b/scripts/gen_relocate_app.py @@ -12,8 +12,9 @@ are given to this python script in the form of a string. Example of such a string would be:: - SRAM2:/home/xyz/zephyr/samples/hello_world/src/main.c,\ - SRAM1:/home/xyz/zephyr/samples/hello_world/src/main2.c + SRAM2:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c,\ + SRAM1:COPY:/home/xyz/zephyr/samples/hello_world/src/main2.c, \ + FLASH2:NOCOPY:/home/xyz/zephyr/samples/hello_world/src/main3.c To invoke this script:: @@ -26,6 +27,8 @@ Configuration that needs to be sent to the python script. - If the memory type is appended with _DATA / _TEXT/ _RODATA/ _BSS only the selected memory is placed in the required memory region. Others are ignored. +- COPY/NOCOPY defines whether the script should generate the relocation code in + code_relocation.c or not Multiple regions can be appended together like SRAM2_DATA_BSS this will place data and bss inside SRAM2. @@ -56,6 +59,11 @@ GROUP_DATA_LINK_IN({0}, FLASH) GROUP_DATA_LINK_IN({0}, {0}) #endif """ + +LOAD_ADDRESS_LOCATION_FLASH_NOCOPY = """ +GROUP_LINK_IN({0}) +""" + LOAD_ADDRESS_LOCATION_BSS = "GROUP_LINK_IN({0})" MPU_RO_REGION_START = """ @@ -236,10 +244,13 @@ def print_linker_sections(list_sections): def string_create_helper(region, memory_type, - full_list_of_sections, load_address_in_flash): + full_list_of_sections, load_address_in_flash, is_copy): linker_string = '' if load_address_in_flash: - load_address_string = LOAD_ADDRESS_LOCATION_FLASH.format(memory_type) + if is_copy: + load_address_string = LOAD_ADDRESS_LOCATION_FLASH.format(memory_type) + else: + load_address_string = LOAD_ADDRESS_LOCATION_FLASH_NOCOPY.format(memory_type) else: load_address_string = LOAD_ADDRESS_LOCATION_BSS.format(memory_type) if full_list_of_sections[region]: @@ -278,19 +289,24 @@ def generate_linker_script(linker_file, sram_data_linker_file, sram_bss_linker_f for memory_type, full_list_of_sections in \ sorted(complete_list_of_sections.items()): - if memory_type != "SRAM": + is_copy = bool("|COPY" in memory_type) + memory_type = memory_type.split("|", 1)[0] + + if memory_type != "SRAM" 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) - gen_string += string_create_helper("rodata", memory_type, full_list_of_sections, 1) - if memory_type != "SRAM": + + 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: gen_string += MPU_RO_REGION_END.format(memory_type.lower()) if memory_type == 'SRAM': - gen_string_sram_data += string_create_helper("data", memory_type, full_list_of_sections, 1) - gen_string_sram_bss += string_create_helper("bss", memory_type, full_list_of_sections, 0) + 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: - gen_string += string_create_helper("data", memory_type, full_list_of_sections, 1) - gen_string += string_create_helper("bss", memory_type, full_list_of_sections, 0) + gen_string += string_create_helper("data", memory_type, full_list_of_sections, 1, 1) + gen_string += string_create_helper("bss", memory_type, full_list_of_sections, 0, 1) # finally writing to the linker file with open(linker_file, "w") as file_desc: @@ -402,7 +418,7 @@ def create_dict_wrt_mem(): if ':' not in line: continue - mem_region, file_name = line.split(':', 1) + mem_region, file_name, copy_flag = line.split(':', 2) file_name_list = glob.glob(file_name) if not file_name_list: @@ -412,6 +428,9 @@ def create_dict_wrt_mem(): continue if args.verbose: print("Memory region ", mem_region, " Selected for file:", file_name_list) + + mem_region = "|".join((mem_region, copy_flag)) + if mem_region in rel_dict: rel_dict[mem_region].extend(file_name_list) else: @@ -456,7 +475,10 @@ def main(): code_generation = {"copy_code": '', "zero_code": '', "extern": ''} for mem_type, list_of_sections in sorted(complete_list_of_sections.items()): - code_generation = generate_memcpy_code(mem_type, + + if "|COPY" in mem_type: + mem_type = mem_type.split("|", 1)[0] + code_generation = generate_memcpy_code(mem_type, list_of_sections, code_generation) dump_header_file(args.output_code, code_generation)