From 9bad1f38e8f0a105f464b93490d79fb636d4a1a0 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Fri, 21 May 2021 21:34:58 +0200 Subject: [PATCH 01/20] scripts: gen_handles.py: take device start symbol as argument. The current gen_handles.py script uses linker defined symbols. As preparation for support of more linkers the gen_tables.py now takes the device start symbol as argument. For example, armlink and ld uses different symbols. With ld those can be named explicitly, but for armlink the linker decides the names. For ld, Zephyr defines: __device_start For armlink, the symbol is defined as: Image$$
$$Base Therefore knowledge of the linker symbol to be used must be passed to gen_handles.py so that the correct symbol can be used for locating devices. To support this change, the creation of the asm, compiler, compiler-cpp, linker targets has been moved from target_toolchain_flags.cmake to target_toolchain.cmake. All linkers has been updated to support the use of the device_start_symbol on the linker target. List of linkers updated: - ld - lld - arcmwdt Signed-off-by: Torsten Rasmussen --- CMakeLists.txt | 1 + cmake/linker/arcmwdt/target.cmake | 1 + cmake/linker/ld/target.cmake | 1 + cmake/linker/lld/target.cmake | 1 + cmake/target_toolchain.cmake | 6 ++++++ cmake/target_toolchain_flags.cmake | 6 ------ scripts/gen_handles.py | 14 ++++++++++---- 7 files changed, 20 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59f861039eb22c..4a41792546da67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -795,6 +795,7 @@ if(CONFIG_HAS_DTS) --output-source dev_handles.c --kernel $ --zephyr-base ${ZEPHYR_BASE} + --start-symbol "$" DEPENDS ${ZEPHYR_PREBUILT_EXECUTABLE} ) set_property(GLOBAL APPEND PROPERTY GENERATED_KERNEL_SOURCE_FILES dev_handles.c) diff --git a/cmake/linker/arcmwdt/target.cmake b/cmake/linker/arcmwdt/target.cmake index 4675f9344d5cd1..9c0a6271e08f1a 100644 --- a/cmake/linker/arcmwdt/target.cmake +++ b/cmake/linker/arcmwdt/target.cmake @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 +set_property(TARGET linker PROPERTY devices_start_symbol "__device_start") find_program(CMAKE_LINKER ${CROSS_COMPILE}lldac PATH ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) diff --git a/cmake/linker/ld/target.cmake b/cmake/linker/ld/target.cmake index 571964fcbe9345..2bef796673f01c 100644 --- a/cmake/linker/ld/target.cmake +++ b/cmake/linker/ld/target.cmake @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 +set_property(TARGET linker PROPERTY devices_start_symbol "__device_start") if(DEFINED TOOLCHAIN_HOME) # When Toolchain home is defined, then we are cross-compiling, so only look diff --git a/cmake/linker/lld/target.cmake b/cmake/linker/lld/target.cmake index a4d0b2f915d136..6aca2d6f35bc01 100644 --- a/cmake/linker/lld/target.cmake +++ b/cmake/linker/lld/target.cmake @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 +set_property(TARGET linker PROPERTY devices_start_symbol "__device_start") find_program(CMAKE_LINKER ld.lld ) diff --git a/cmake/target_toolchain.cmake b/cmake/target_toolchain.cmake index 1edb6385172819..0d8bbc2d32d0ca 100644 --- a/cmake/target_toolchain.cmake +++ b/cmake/target_toolchain.cmake @@ -32,6 +32,12 @@ set(CMAKE_SYSTEM_VERSION ${PROJECT_VERSION}) # We are not building dynamically loadable libraries set(BUILD_SHARED_LIBS OFF) +# Custom targets for compiler and linker flags. +add_custom_target(asm) +add_custom_target(compiler) +add_custom_target(compiler-cpp) +add_custom_target(linker) + if(NOT (COMPILER STREQUAL "host-gcc")) include(${TOOLCHAIN_ROOT}/cmake/toolchain/${ZEPHYR_TOOLCHAIN_VARIANT}/target.cmake) endif() diff --git a/cmake/target_toolchain_flags.cmake b/cmake/target_toolchain_flags.cmake index b74c3e787220cc..35c1fb08f4f698 100644 --- a/cmake/target_toolchain_flags.cmake +++ b/cmake/target_toolchain_flags.cmake @@ -24,12 +24,6 @@ set(TOOLCHAIN_SIGNATURE ${CMAKE_C_COMPILER_MD5_SUM}) string(MD5 COMPILER_SIGNATURE ${CMAKE_C_COMPILER}_${CMAKE_C_COMPILER_ID}_${CMAKE_C_COMPILER_VERSION}) set(TOOLCHAIN_SIGNATURE ${TOOLCHAIN_SIGNATURE}_${COMPILER_SIGNATURE}) -# Custom targets for compiler and linker flags. -add_custom_target(asm) -add_custom_target(compiler) -add_custom_target(compiler-cpp) -add_custom_target(linker) - # Loading of templates are strictly not needed as they does not set any # properties. # They purely provides an overview as well as a starting point for supporting diff --git a/scripts/gen_handles.py b/scripts/gen_handles.py index 441ad6419a4580..c8354d9ec8385b 100755 --- a/scripts/gen_handles.py +++ b/scripts/gen_handles.py @@ -73,6 +73,11 @@ def parse_args(): is not provided the environment will be checked for \ the ZEPHYR_BASE environment variable.") + parser.add_argument("-s", "--start-symbol", required=True, + help="Symbol name of the section which contains the \ + devices. The symbol name must point to the first \ + device in that section.") + args = parser.parse_args() if "VERBOSE" in os.environ: args.verbose = 1 @@ -145,7 +150,7 @@ def obj_handles(self): else: format += "Q" size = 8 - offset = self.ld_constants["DEVICE_STRUCT_HANDLES_OFFSET"] + offset = self.ld_constants["_DEVICE_STRUCT_HANDLES_OFFSET"] self.__handles = struct.unpack(format, data[offset:offset + size])[0] return self.__handles @@ -172,7 +177,8 @@ def main(): devices = [] handles = [] # Leading _ are stripped from the stored constant key - want_constants = set(["__device_start", + + want_constants = set([args.start_symbol, "_DEVICE_STRUCT_SIZEOF", "_DEVICE_STRUCT_HANDLES_OFFSET"]) ld_constants = dict() @@ -181,7 +187,7 @@ def main(): if isinstance(section, SymbolTableSection): for sym in section.iter_symbols(): if sym.name in want_constants: - ld_constants[sym.name.lstrip("_")] = sym.entry.st_value + ld_constants[sym.name] = sym.entry.st_value continue if sym.entry.st_info.type != 'STT_OBJECT': continue @@ -204,7 +210,7 @@ def main(): devices = sorted(devices, key = lambda k: k.sym.entry.st_value) - device_start_addr = ld_constants["device_start"] + device_start_addr = ld_constants[args.start_symbol] device_size = 0 assert len(devices) == len(handles), 'mismatch devices and handles' From 7a2a9a8e4763ba6ccc2100c9f6dfb744a56a3e52 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Tue, 20 Apr 2021 13:53:55 +0200 Subject: [PATCH 02/20] asm: .eabi_attribute Tag_ABI_align_preserved, 1 Tell armlink that files has ensured proper stack alignment. Signed-off-by: Torsten Rasmussen --- arch/arm/core/aarch32/cortex_m/vector_table.S | 4 ++++ arch/arm/core/aarch32/isr_wrapper.S | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/core/aarch32/cortex_m/vector_table.S b/arch/arm/core/aarch32/cortex_m/vector_table.S index 8dcd4e06417922..d73aabdcb544ec 100644 --- a/arch/arm/core/aarch32/cortex_m/vector_table.S +++ b/arch/arm/core/aarch32/cortex_m/vector_table.S @@ -22,6 +22,10 @@ #include "vector_table.h" _ASM_FILE_PROLOGUE +/* + * Tell armclang that stack alignment are ensured. + */ +.eabi_attribute Tag_ABI_align_preserved, 1 GDATA(z_main_stack) diff --git a/arch/arm/core/aarch32/isr_wrapper.S b/arch/arm/core/aarch32/isr_wrapper.S index f62ad0fc1b634d..0f60ade2ca36c8 100644 --- a/arch/arm/core/aarch32/isr_wrapper.S +++ b/arch/arm/core/aarch32/isr_wrapper.S @@ -12,6 +12,10 @@ * Wrapper installed in vector table for handling dynamic interrupts that accept * a parameter. */ +/* + * Tell armclang that stack alignment are ensured. + */ +.eabi_attribute Tag_ABI_align_preserved, 1 #include #include From db796aff9cecae6037f083c2d8079ffa5afb268c Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Thu, 10 Jun 2021 13:18:36 +0200 Subject: [PATCH 03/20] cmake: CMake linker functions implemented This commit introduces zephyr_linker CMake functions for creation of linker scripts. The linker functions supports the following features: - Configuration of memory sections - Configuration of memory groups - Creation of output sections - Configuration of input section the should go into output section and how those should be treated, such as sorting, keep, priority. - Defining linker symbols - Specifying Kernel VMA to support virtual linking on x86 Overview of functions and macros introduce with this commit: - pow2round - zephyr_linker - zephyr_linker_memory - zephyr_linker_memory_ifdef - zephyr_linker_group - zephyr_linker_section - zephyr_linker_section_ifdef - zephyr_iterable_section - zephyr_linker_section_obj_level - zephyr_linker_section_configure - zephyr_linker_symbol - zephyr_linker_property_append Signed-off-by: Torsten Rasmussen --- cmake/extensions.cmake | 649 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 649 insertions(+) diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index 9fe246f31ee47c..be85fdedc4bbab 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -21,6 +21,8 @@ # 3.5. File system management # 4. Devicetree extensions # 4.1 dt_* +# 5. Zephyr linker functions +# 5.1. zephyr_linker* ######################################################## # 1. Zephyr-aware extensions @@ -1248,6 +1250,38 @@ function(check_dtc_flag flag ok) endif() endfunction() +# Function to round number to next power of two. +# +# Usage: +# pow2round() +# +# Example: +# set(test 2) +# pow2round(test) +# # test is still 2 +# +# set(test 5) +# pow2round(test) +# # test is now 8 +# +# Arguments: +# n = Variable containing the number to round +function(pow2round n) + math(EXPR x "${${n}} & (${${n}} - 1)") + if(${x} EQUAL 0) + return() + endif() + + math(EXPR ${n} "${${n}} | (${${n}} >> 1)") + math(EXPR ${n} "${${n}} | (${${n}} >> 2)") + math(EXPR ${n} "${${n}} | (${${n}} >> 4)") + math(EXPR ${n} "${${n}} | (${${n}} >> 8)") + math(EXPR ${n} "${${n}} | (${${n}} >> 16)") + math(EXPR ${n} "${${n}} | (${${n}} >> 32)") + math(EXPR ${n} "${${n}} + 1") + set(${n} ${${n}} PARENT_SCOPE) +endfunction() + ######################################################## # 2. Kconfig-aware extensions ######################################################## @@ -2809,3 +2843,618 @@ function(dt_chosen var) set(${var} ${${var}} PARENT_SCOPE) endif() endfunction() + +######################################################## +# 5. Zephyr linker function +######################################################## +# 5.1. zephyr_linker* +# +# The following methods are for defining linker structure using CMake functions. +# +# This allows Zephyr developers to define linker sections and their content and +# have this configuration rendered into an appropriate linker script based on +# the toolchain in use. +# For example: +# ld linker scripts with GNU ld +# ARM scatter files with ARM linker. +# +# Example usage: +# zephyr_linker_section( +# NAME my_data +# VMA RAM +# LMA FLASH +# ) +# +# and to configure special input sections for the section +# zephyr_linker_section_configure( +# SECTION my_data +# INPUT "my_custom_data" +# KEEP +# ) + + +# Usage: +# zephyr_linker([FORMAT ] +# [ENTRY ] +# ) +# +# Zephyr linker general settings. +# This function specifies general settings for the linker script to be generated. +# +# FORMAT : The output format of the linked executable. +# ENTRY : The code entry symbol. +# +function(zephyr_linker) + set(single_args "ENTRY;FORMAT") + cmake_parse_arguments(LINKER "" "${single_args}" "" ${ARGN}) + + if(LINKER_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_linker(${ARGV0} ...) given unknown " + "arguments: ${LINKER_UNPARSED_ARGUMENTS}" + ) + endif() + + if(DEFINED LINKER_FORMAT) + get_property(format_defined TARGET linker PROPERTY FORMAT SET) + if(format_defined) + message(FATAL_ERROR "zephyr_linker(FORMAT ...) already configured.") + else() + set_property(TARGET linker PROPERTY FORMAT ${LINKER_FORMAT}) + endif() + endif() + + if(DEFINED LINKER_ENTRY) + get_property(entry_defined TARGET linker PROPERTY ENTRY SET) + if(entry_defined) + message(FATAL_ERROR "zephyr_linker(ENTRY ...) already configured.") + else() + set_property(TARGET linker PROPERTY ENTRY ${LINKER_ENTRY}) + endif() + endif() +endfunction() + +# Usage: +# zephyr_linker_memory(NAME START
SIZE FLAGS ) +# +# Zephyr linker memory. +# This function specifies a memory region for the platform in use. +# +# Note: +# This function should generally be called with values obtained from +# devicetree or Kconfig. +# +# NAME : Name of the memory region, for example FLASH. +# START
: Start address of the memory region. +# Start address can be given as decimal or hex value. +# SIZE : Size of the memory region. +# Size can be given as decimal value, hex value, or decimal with postfix k or m. +# All the following are valid values: +# 1048576, 0x10000, 1024k, 1024K, 1m, and 1M. +# FLAGS : Flags describing properties of the memory region. +# Currently supported: +# r: Read-only region +# w: Read-write region +# x: Executable region +# The flags r and x, or w and x may be combined like: rx, wx. +function(zephyr_linker_memory) + set(single_args "FLAGS;NAME;SIZE;START") + cmake_parse_arguments(MEMORY "" "${single_args}" "" ${ARGN}) + + if(MEMORY_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) given unknown " + "arguments: ${MEMORY_UNPARSED_ARGUMENTS}" + ) + endif() + + foreach(arg ${single_args}) + if(NOT DEFINED MEMORY_${arg}) + message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) missing required " + "argument: ${arg}" + ) + endif() + endforeach() + + set(MEMORY) + zephyr_linker_arg_val_list(MEMORY "${single_args}") + + string(REPLACE ";" "\;" MEMORY "${MEMORY}") + set_property(TARGET linker + APPEND PROPERTY MEMORY_REGIONS "{${MEMORY}}" + ) +endfunction() + +# Usage: +# zephyr_linker_memory_ifdef( NAME START
SIZE FLAGS ) +# +# Will create memory region if is enabled. +# +# : Setting to check for True value before invoking +# zephyr_linker_memory() +# +# See zephyr_linker_memory() description for other supported arguments. +# +macro(zephyr_linker_memory_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_linker_memory(${ARGN}) + endif() +endmacro() + +# Usage: +# zephyr_linker_group(NAME [VMA ] [LMA ]) +# zephyr_linker_group(NAME GROUP ) +# +# Zephyr linker group. +# This function specifies a group inside a memory region or another group. +# +# The group ensures that all section inside the group are located together inside +# the specified group. +# +# This also allows for section placement inside a given group without the section +# itself needing the precise knowledge regarding the exact memory region this +# section will be placed in, as that will be determined by the group setup. +# +# Each group will define the following linker symbols: +# ___start : Start address of the group +# ___end : End address of the group +# ___size : Size of the group +# +# Note: will be converted to lower casing for linker symbols definitions. +# +# NAME : Name of the group. +# VMA : VMA Memory region or group to be used for this group. +# If a group is used then the VMA region of that group will be used. +# LMA : Memory region or group to be used for this group. +# GROUP : Place the new group inside the existing group +# +# Note: VMA and LMA are mutual exclusive with GROUP +# +# Example: +# zephyr_linker_memory(NAME memA START ... SIZE ... FLAGS ...) +# zephyr_linker_group(NAME groupA LMA memA) +# zephyr_linker_group(NAME groupB LMA groupA) +# +# will create two groups in same memory region as groupB will inherit the LMA +# from groupA: +# +# +-----------------+ +# | memory region A | +# | | +# | +-------------+ | +# | | groupA | | +# | +-------------+ | +# | | +# | +-------------+ | +# | | groupB | | +# | +-------------+ | +# | | +# +-----------------+ +# +# whereas +# zephyr_linker_memory(NAME memA START ... SIZE ... FLAGS ...) +# zephyr_linker_group(NAME groupA LMA memA) +# zephyr_linker_group(NAME groupB GROUP groupA) +# +# will create groupB inside groupA: +# +# +---------------------+ +# | memory region A | +# | | +# | +-----------------+ | +# | | groupA | | +# | | | | +# | | +-------------+ | | +# | | | groupB | | | +# | | +-------------+ | | +# | | | | +# | +-----------------+ | +# | | +# +---------------------+ +function(zephyr_linker_group) + set(single_args "NAME;GROUP;LMA;VMA") + cmake_parse_arguments(GROUP "" "${single_args}" "" ${ARGN}) + + if(GROUP_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_linker_group(${ARGV0} ...) given unknown " + "arguments: ${GROUP_UNPARSED_ARGUMENTS}" + ) + endif() + + if(DEFINED GROUP_GROUP AND (DEFINED GROUP_VMA OR DEFINED GROUP_LMA)) + message(FATAL_ERROR "zephyr_linker_group(GROUP ...) cannot be used with " + "VMA or LMA" + ) + endif() + + set(GROUP) + zephyr_linker_arg_val_list(GROUP "${single_args}") + + string(REPLACE ";" "\;" GROUP "${GROUP}") + set_property(TARGET linker + APPEND PROPERTY GROUPS "{${GROUP}}" + ) +endfunction() + +# Usage: +# zephyr_linker_section(NAME [GROUP ] +# [VMA ] [LMA ] +# [ADDRESS
] [ALIGN ] +# [SUBALIGN ] [FLAGS ] +# [HIDDEN] [NOINPUT] [NOINIT] +# [PASS [...] +# ) +# +# Zephyr linker output section. +# This function specifies an output section for the linker. +# +# When using zephyr_linker_section(NAME ) an output section with +# will be configured. This section will default include input sections of the +# same name, unless NOINPUT is specified. +# This means the section named `foo` will default include the sections matching +# `foo` and `foo.*` +# Each output section will define the following linker symbols: +# ___start : Start address of the section +# ___end : End address of the section +# ___size : Size of the section +# ___load_start : Load address of the section, if VMA = LMA then this +# value will be identical to `___start` +# +# The location of the output section can be controlled using LMA, VMA, and +# address parameters +# +# NAME : Name of the output section. +# VMA : VMA Memory region or group where code / data is located runtime (VMA) +# If is used here it means the section will use the +# same VMA memory region as but will not be placed +# inside the group itself, see also GROUP argument. +# KVMA : Kernel VMA Memory region or group where code / data is located runtime (VMA) +# When MMU is active and Kernel VM base and offset is different +# from SRAM base and offset, then the region defined by KVMA will +# be used as VMA. +# If is used here it means the section will use the +# same VMA memory region as but will not be placed +# inside the group itself, see also GROUP argument. +# LMA : Memory region or group where code / data is loaded (LMA) +# If VMA is different from LMA, the code / data will be loaded +# from LMA into VMA at bootup, this is usually the case for +# global or static variables that are loaded in rom and copied +# to ram at boot time. +# If is used here it means the section will use the +# same LMA memory region as but will not be placed +# inside the group itself, see also GROUP argument. +# GROUP : Place this section inside the group +# ADDRESS
: Specific address to use for this section. +# ALIGN_WITH_INPUT : The alignment difference between VMA and LMA is kept +# intact for this section. +# ALIGN : Align the execution address with alignment. +# SUBALIGN : Align input sections with alignment value. +# ENDALIGN : Align the end so that next output section will start aligned. +# This only has effect on Scatter scripts. +# Note: Regarding all alignment attributes. Not all linkers may handle alignment +# in identical way. For example the Scatter file will align both load and +# execution address (LMA and VMA) to be aligned when given the ALIGN attribute. +# NOINPUT : No default input sections will be defined, to setup input +# sections for section , the corresponding +# `zephyr_linker_section_configure()` must be used. +# PASS [ ..] : Linker pass iteration where this section should be active. +# Default a section will be present during all linker passes +# But in cases a section shall only be present at a specific +# pass, this argument can be used. For example to only have +# this section present on the first linker pass, use `PASS 1`. +# +# Note: VMA and LMA are mutual exclusive with GROUP +# +function(zephyr_linker_section) + set(options "ALIGN_WITH_INPUT;HIDDEN;NOINIT;NOINPUT") + set(single_args "ADDRESS;ALIGN;ENDALIGN;GROUP;KVMA;LMA;NAME;SUBALIGN;TYPE;VMA") + set(multi_args "PASS") + cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN}) + + if(SECTION_UNPARSED_ARGUMENTS) + message(WARNING "zephyr_linker_section(${ARGV0} ...) given unknown " + "arguments: ${SECTION_UNPARSED_ARGUMENTS}" + ) + endif() + + if(DEFINED SECTION_GROUP AND (DEFINED SECTION_VMA OR DEFINED SECTION_LMA)) + message(FATAL_ERROR "zephyr_linker_section(GROUP ...) cannot be used with " + "VMA or LMA" + ) + endif() + + if(DEFINED SECTION_KVMA) + # If KVMA is set and the Kernel virtual memory settings reqs are met, we + # substitute the VMA setting with the specified KVMA value. + if(CONFIG_MMU) + math(EXPR KERNEL_MEM_VM_OFFSET + "(${CONFIG_KERNEL_VM_BASE} + ${CONFIG_KERNEL_VM_OFFSET})\ + - (${CONFIG_SRAM_BASE_ADDRESS} + ${CONFIG_SRAM_OFFSET})" + ) + + if(NOT (${KERNEL_MEM_VM_OFFSET} EQUAL 0)) + set(SECTION_VMA ${SECTION_KVMA}) + set(SECTION_KVMA) + endif() + endif() + endif() + + set(SECTION) + zephyr_linker_arg_val_list(SECTION "${single_args}") + zephyr_linker_arg_val_list(SECTION "${options}") + zephyr_linker_arg_val_list(SECTION "${multi_args}") + + string(REPLACE ";" "\;" SECTION "${SECTION}") + set_property(TARGET linker + APPEND PROPERTY SECTIONS "{${SECTION}}" + ) +endfunction() + +# Usage: +# zephyr_linker_section_ifdef( +# NAME [VMA ] [LMA ] +# [ADDRESS
] [ALIGN ] +# [SUBALIGN ] [FLAGS ] +# [HIDDEN] [NOINPUT] [NOINIT] +# [PASS [...] +# ) +# +# Will create an output section if is enabled. +# +# : Setting to check for True value before invoking +# zephyr_linker_section() +# +# See zephyr_linker_section() description for other supported arguments. +# +macro(zephyr_linker_section_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_linker_section(${ARGN}) + endif() +endmacro() + +# Usage: +# zephyr_iterable_section(NAME [GROUP ] +# [VMA ] [LMA ] +# [ALIGN_WITH_INPUT] [SUBALIGN ] +# ) +# +# +# Define an output section which will set up an iterable area +# of equally-sized data structures. For use with Z_STRUCT_SECTION_ITERABLE. +# Input sections will be sorted by name in lexicographical order. +# +# Each list for an input section will define the following linker symbols: +# __list_start: Start of the iterable list +# __list_end : End of the iterable list +# +# The output section will be named `_area` and define the following linker +# symbols: +# ___area_start : Start address of the section +# ___area_end : End address of the section +# ___area_size : Size of the section +# ___area_load_start : Load address of the section, if VMA = LMA then this +# value will be identical to `___area_start` +# +# NAME : Name of the struct type, the output section be named +# accordingly as: _area. +# VMA : VMA Memory region where code / data is located runtime (VMA) +# LMA : Memory region where code / data is loaded (LMA) +# If VMA is different from LMA, the code / data will be loaded +# from LMA into VMA at bootup, this is usually the case for +# global or static variables that are loaded in rom and copied +# to ram at boot time. +# GROUP : Place this section inside the group +# ADDRESS
: Specific address to use for this section. +# ALIGN_WITH_INPUT : The alignment difference between VMA and LMA is kept +# intact for this section. +# SUBALIGN : Force input alignment with size +# Note: Regarding all alignment attributes. Not all linkers may handle alignment +# in identical way. For example the Scatter file will align both load and +# execution address (LMA and VMA) to be aligned when given the ALIGN attribute. +#/ +function(zephyr_iterable_section) + # ToDo - Should we use ROM, RAM, etc as arguments ? + set(options "ALIGN_WITH_INPUT") + set(single_args "GROUP;LMA;NAME;SUBALIGN;VMA") + set(multi_args "") + set(align_input) + cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN}) + + if(NOT DEFINED SECTION_NAME) + message(FATAL_ERROR "zephyr_iterable_section(${ARGV0} ...) missing " + "required argument: NAME" + ) + endif() + + if(NOT DEFINED SECTION_SUBALIGN) + message(FATAL_ERROR "zephyr_iterable_section(${ARGV0} ...) missing " + "required argument: SUBALIGN" + ) + endif() + + if(SECTION_ALIGN_WITH_INPUT) + set(align_input ALIGN_WITH_INPUT) + endif() + + zephyr_linker_section( + NAME ${SECTION_NAME}_area + GROUP "${SECTION_GROUP}" + VMA "${SECTION_VMA}" LMA "${SECTION_LMA}" + NOINPUT ${align_input} SUBALIGN ${SECTION_SUBALIGN} + ) + zephyr_linker_section_configure( + SECTION ${SECTION_NAME}_area + INPUT "._${SECTION_NAME}.static.*" + SYMBOLS _${SECTION_NAME}_list_start _${SECTION_NAME}_list_end + KEEP SORT NAME + ) +endfunction() + +# Usage: +# zephyr_linker_section_obj_level(SECTION
LEVEL ) +# +# generate a symbol to mark the start of the objects array for +# the specified object and level, then link all of those objects +# (sorted by priority). Ensure the objects aren't discarded if there is +# no direct reference to them. +# +# This is useful content such as struct devices. +# +# For example: zephyr_linker_section_obj_level(SECTION init LEVEL PRE_KERNEL_1) +# will create an input section matching `.z_init_PRE_KERNEL_1?_` and +# `.z_init_PRE_KERNEL_1??_`. +# +# SECTION
: Section in which the objects shall be placed +# LEVEL : Priority level, all input sections matching the level +# will be sorted. +# +function(zephyr_linker_section_obj_level) + set(single_args "SECTION;LEVEL") + cmake_parse_arguments(OBJ "" "${single_args}" "" ${ARGN}) + + if(NOT DEFINED OBJ_SECTION) + message(FATAL_ERROR "zephyr_linker_section_obj_level(${ARGV0} ...) " + "missing required argument: SECTION" + ) + endif() + + if(NOT DEFINED OBJ_LEVEL) + message(FATAL_ERROR "zephyr_linker_section_obj_level(${ARGV0} ...) " + "missing required argument: LEVEL" + ) + endif() + + zephyr_linker_section_configure( + SECTION ${OBJ_SECTION} + INPUT ".z_${OBJ_SECTION}_${OBJ_LEVEL}?_" + SYMBOLS __${OBJ_SECTION}_${OBJ_LEVEL}_start + KEEP SORT NAME + ) + zephyr_linker_section_configure( + SECTION ${OBJ_SECTION} + INPUT ".z_${OBJ_SECTION}_${OBJ_LEVEL}??_" + KEEP SORT NAME + ) +endfunction() + +# Usage: +# zephyr_linker_section_configure(SECTION
[ALIGN ] +# [PASS ] [PRIO ] [SORT ] +# [ANY] [FIRST] [KEEP] +# ) +# +# Configure an output section with additional input sections. +# An output section can be configured with additional input sections besides its +# default section. +# For example, adding the input section `foo` to the output section bar, with KEEP +# attribute, then call: +# zephyr_linker_section_configure(SECTION bar INPUT foo KEEP) +# +# ALIGN : Will align the input section placement inside the load +# region with +# FIRST : The first input section in the list should be marked as +# first section in output. +# SORT : Sort the input sections according to . +# Currently only `NAME` is supported. +# KEEP : Do no eliminate input section during linking +# PRIO : The priority of the input section. Per default, input +# sections order is not guaranteed by all linkers, but +# using priority, then Zephyr CMake linker will create +# sections so order can be guaranteed. All unprioritized +# sections will internally be given a CMake process order +# priority counting from 100, so first unprioritized section +# is handles internal pri0 100, next 101, and so on. +# To ensure a specific input section come before those, +# you may use `PRIO 50`, `PRIO 20` and so on. +# To ensure an input section is at the end, it is advised +# to use `PRIO 200` and above. +# PASS : The call should only be considered for linker pass number . +# For example, `PASS 1` means the call is only effective +# on first linker pass iteration. `PASS 2` on second iteration, +# and so on. +# FLAGS : Special section flags such as "+RO", +XO, "+ZI". +# ANY : ANY section flag in scatter file. +# The FLAGS and ANY arguments only has effect for scatter files. +# +function(zephyr_linker_section_configure) + set(options "ANY;FIRST;KEEP") + set(single_args "ALIGN;OFFSET;PASS;PRIO;SECTION;SORT") + set(multi_args "FLAGS;INPUT;SYMBOLS") + cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN}) + + if(SECTION_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_linker_section_configure(${ARGV0} ...) given unknown arguments: ${SECTION_UNPARSED_ARGUMENTS}") + endif() + + if(DEFINED SECTION_SYMBOLS) + list(LENGTH SECTION_SYMBOLS symbols_count) + if(${symbols_count} GREATER 2) + message(FATAL_ERROR "zephyr_linker_section_configure(SYMBOLS [start_sym [end_sym]]) takes maximum two symbol names (start and end).") + + endif() + endif() + + set(SECTION) + zephyr_linker_arg_val_list(SECTION "${single_args}") + zephyr_linker_arg_val_list(SECTION "${options}") + zephyr_linker_arg_val_list(SECTION "${multi_args}") + + string(REPLACE ";" "\;" SECTION "${SECTION}") + set_property(TARGET linker + APPEND PROPERTY SECTION_SETTINGS "{${SECTION}}" + ) +endfunction() + +# Usage: +# zephyr_linker_symbol(SYMBOL EXPR ) +# +# Add additional user defined symbol to the generated linker script. +# +# SYMBOL : Symbol name to be available. +# EXPR : Expression that defines the symbol. Due to linker limitations +# all expressions should only contain simple math, such as +# `+, -, *` and similar. The expression will go directly into the +# linker, and all `%%` will be replaced with the referred +# symbol. +# +# Example: +# To create a new symbol `bar` pointing to the start VMA address of section +# `foo` + 1024, one can write: +# zephyr_linker_symbol(SYMBOL bar EXPR "(%foo% + 1024)") +# +function(zephyr_linker_symbol) + set(single_args "EXPR;SYMBOL") + cmake_parse_arguments(SYMBOL "" "${single_args}" "" ${ARGN}) + + if(SECTION_UNPARSED_ARGUMENTS) + message(WARNING "zephyr_linker_symbol(${ARGV0} ...) given unknown " + "arguments: ${SECTION_UNPARSED_ARGUMENTS}" + ) + endif() + + set(SYMBOL) + zephyr_linker_arg_val_list(SYMBOL "${single_args}") + + string(REPLACE ";" "\;" SYMBOL "${SYMBOL}") + set_property(TARGET linker + APPEND PROPERTY SYMBOLS "{${SYMBOL}}" + ) +endfunction() + +# Internal helper macro for zephyr_linker*() functions. +# The macro will create a list of argument-value pairs for defined arguments +# that can be passed on to linker script generators and processed as a CMake +# function call using cmake_parse_arguments. +# +# For example, having the following argument and value: +# FOO: bar +# BAZ: +# QUX: option set +# +# will create a list as: "FOO;bar;QUX:TRUE" which can then be parsed as argument +# list later. +macro(zephyr_linker_arg_val_list list arguments) + foreach(arg ${arguments}) + if(DEFINED ${list}_${arg}) + list(APPEND ${list} ${arg} "${${list}_${arg}}") + endif() + endforeach() +endmacro() From cf9f2c43a67ddc2c5ec1642b9a3e5b4a46474dca Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 11 Aug 2021 17:00:02 +0200 Subject: [PATCH 04/20] cmake: CMake devicetree related linker functions implemented This commit introduces zephyr_linker_dts CMake functions for creation of linker scripts based on devicetree nodes. The linker devicetree functions supports the following features: - Configuration of memory sections based on devicetree nodes Overview of functions introduced with this commit: - zephyr_linker_dts_memory Signed-off-by: Torsten Rasmussen --- cmake/extensions.cmake | 71 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index be85fdedc4bbab..b5fe2898be1fd4 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -2979,6 +2979,77 @@ macro(zephyr_linker_memory_ifdef feature_toggle) endif() endmacro() +# Usage: +# zephyr_linker_dts_memory(NAME PATH FLAGS ) +# zephyr_linker_dts_memory(NAME NODELABEL FLAGS ) +# zephyr_linker_dts_memory(NAME CHOSEN FLAGS ) +# +# Zephyr linker devicetree memory. +# This function specifies a memory region for the platform in use based on its +# devicetree configuration. +# +# The memory will only be defined if the devicetree node or a devicetree node +# matching the nodelabel exists and has status okay. +# +# Only one of PATH, NODELABEL, and CHOSEN parameters may be given. +# +# NAME : Name of the memory region, for example FLASH. +# PATH : Devicetree node identifier. +# NODELABEL