Skip to content

Delay relocation of data/bss init after MEMC init is completed #68888

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,17 @@ config CODE_DATA_RELOCATION
the target regions should be specified in CMakeLists.txt using
zephyr_code_relocate().

config DELAY_DATA_RELOCATION
bool "Support delayed data relocation/bss init"
depends on ARCH_HAS_CODE_DATA_RELOCATION
depends on CODE_DATA_RELOCATION
Comment on lines +869 to +870
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE_DATA_RELOCATION already depends on ARCH_HAS_CODE_DATA_RELOCATION, no need to add it again.

Suggested change
depends on ARCH_HAS_CODE_DATA_RELOCATION
depends on CODE_DATA_RELOCATION
depends on CODE_DATA_RELOCATION

help
Enable support for delaying data relocation and bss zero initialization. Enable this option when
relocation must be delayed after the device driver initialization is finished.
Delayed relocation will only be applied to memory regions (compatible zephyr,memory-region)
which have delay-relocation property set. The delayed routines will be run
after PRE_KERNEL_1 initialization has completed.

menu "DSP Options"

config DSP_SHARING
Expand Down
8 changes: 6 additions & 2 deletions cmake/linker/ld/target_relocation.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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")
set(MEM_DELAYED_RELOCATION_CODE "${PROJECT_BINARY_DIR}/code_relocation_delayed.c")
set(MEM_REGION_DEFAULT_RAM RAM)
set(DICT_FILE "${PROJECT_BINARY_DIR}/relocation_dict.txt")

Expand All @@ -20,7 +21,7 @@ macro(toolchain_ld_relocation)
)

add_custom_command(
OUTPUT ${MEM_RELOCATION_CODE} ${MEM_RELOCATION_LD}
OUTPUT ${MEM_RELOCATION_CODE} ${MEM_DELAYED_RELOCATION_CODE} ${MEM_RELOCATION_LD}
COMMAND
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/build/gen_relocate_app.py
Expand All @@ -31,11 +32,14 @@ macro(toolchain_ld_relocation)
-s ${MEM_RELOCATION_SRAM_DATA_LD}
-b ${MEM_RELOCATION_SRAM_BSS_LD}
-c ${MEM_RELOCATION_CODE}
--output_code_delayed_relocation ${MEM_DELAYED_RELOCATION_CODE}
--edt_pickle ${EDT_PICKLE}
--default_ram_region ${MEM_REGION_DEFAULT_RAM}
DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} ${DICT_FILE}
DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} ${DICT_FILE} ${EDT_PICKLE}
)

add_library(code_relocation_source_lib STATIC ${MEM_RELOCATION_CODE})
target_sources_ifdef(CONFIG_DELAY_DATA_RELOCATION code_relocation_source_lib PRIVATE ${MEM_DELAYED_RELOCATION_CODE})
target_include_directories(code_relocation_source_lib PRIVATE
${ZEPHYR_BASE}/kernel/include ${ARCH_DIR}/${ARCH}/include)
target_link_libraries(code_relocation_source_lib zephyr_interface)
Expand Down
6 changes: 6 additions & 0 deletions dts/bindings/base/zephyr,memory-region.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@ properties:
memory region in the final executable. The region address and size
is taken from the <reg> property, while the name is the value of
this property.

delay-relocation:
type: boolean
description: |
Delay .data relocation and .bss zero initialization until PRE_KERNEL_1
initialization levels have completed.
11 changes: 10 additions & 1 deletion kernel/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ void z_bss_zero(void)

#ifdef CONFIG_LINKER_USE_BOOT_SECTION
/**
* @brief Clear BSS within the bot region
* @brief Clear BSS within the boot region
*
* This routine clears the BSS within the boot region.
* This is separate from z_bss_zero() as boot region may
Expand Down Expand Up @@ -574,6 +574,15 @@ FUNC_NORETURN void z_cstart(void)

/* perform basic hardware initialization */
z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_1);

#ifdef CONFIG_DELAY_DATA_RELOCATION
extern void bss_zeroing_relocation_delayed(void);
extern void data_copy_xip_relocation_delayed(void);

bss_zeroing_relocation_delayed();
data_copy_xip_relocation_delayed();
#endif /* CONFIG_DELAY_DATA_RELOCATION */

z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_2);

#ifdef CONFIG_STACK_CANARIES
Expand Down
45 changes: 36 additions & 9 deletions scripts/build/gen_relocate_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import argparse
import os
import glob
import pickle
import warnings
from collections import defaultdict
from enum import Enum
Expand All @@ -56,6 +57,10 @@
from elftools.elf.elffile import ELFFile
from elftools.elf.sections import SymbolTableSection

# This is needed to load edt.pickle files.
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..',
'dts', 'python-devicetree', 'src'))

MemoryRegion = NewType('MemoryRegion', str)


Expand Down Expand Up @@ -187,14 +192,14 @@ class OutputSection(NamedTuple):


DATA_COPY_FUNCTION = """
void data_copy_xip_relocation(void)
void data_copy_xip_relocation{1}(void)
{{
{0}
}}
"""

BSS_ZEROING_FUNCTION = """
void bss_zeroing_relocation(void)
void bss_zeroing_relocation{1}(void)
{{
{0}
}}
Expand Down Expand Up @@ -443,21 +448,21 @@ def generate_memcpy_code(memory_type, full_list_of_sections, code_generation):
return code_generation


def dump_header_file(header_file, code_generation):
def dump_header_file(header_file, code_generation, func_name_trailer = ""):
code_string = ''
# create a dummy void function if there is no code to generate for
# bss/data/text regions

code_string += code_generation["extern"]

if code_generation["copy_code"]:
code_string += DATA_COPY_FUNCTION.format(code_generation["copy_code"])
code_string += DATA_COPY_FUNCTION.format(code_generation["copy_code"], func_name_trailer)
else:
code_string += DATA_COPY_FUNCTION.format("return;")
code_string += DATA_COPY_FUNCTION.format("return;", func_name_trailer)
if code_generation["zero_code"]:
code_string += BSS_ZEROING_FUNCTION.format(code_generation["zero_code"])
code_string += BSS_ZEROING_FUNCTION.format(code_generation["zero_code"], func_name_trailer)
else:
code_string += BSS_ZEROING_FUNCTION.format("return;")
code_string += BSS_ZEROING_FUNCTION.format("return;", func_name_trailer)

with open(header_file, "w") as header_file_desc:
header_file_desc.write(SOURCE_CODE_INCLUDES)
Expand All @@ -480,8 +485,12 @@ 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("--output_code_delayed_relocation", required=False,
help="Output delayed 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("--edt_pickle", required=False,
help="Path to read the pickled edtlib.EDT object from")
parser.add_argument("-v", "--verbose", action="count", default=0,
help="Verbose Output")
args = parser.parse_args()
Expand Down Expand Up @@ -605,15 +614,33 @@ def main():
generate_linker_script(linker_file, sram_data_linker_file,
sram_bss_linker_file, complete_list_of_sections, phdrs)

delayed_relocate = dict()
if os.path.isfile(args.edt_pickle):
with open(args.edt_pickle, 'rb') as f:
edt = pickle.load(f)
for node in edt.compat2nodes["zephyr,memory-region"]:
delayed_relocate[node.props["zephyr,memory-region"].val] = node.props["delay-relocation"].val

else:
edt = None
Comment on lines +618 to +625
Copy link
Contributor

@jhol jhol Apr 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you really want to handle the file not existing, it would be better instead to handle FileNotFoundError exceptions from open() so that there is no change of a race condition between the check and the use of the file.

But I think it's wrong to set edt = None if the file is not found. It should be set to None only if the args.edt_pickle is not None.

If the --edt_pickle option is given but the file fails to open, then it would probably best to just let the exception go out unhandled.


code_generation = {"copy_code": '', "zero_code": '', "extern": ''}
code_generation_delayed_relocate = {"copy_code": '', "zero_code": '', "extern": ''}
for mem_type, list_of_sections in sorted(complete_list_of_sections.items()):

if "|COPY" in mem_type:
mem_type = mem_type.split("|", 1)[0]
code_generation = generate_memcpy_code(mem_type,
list_of_sections, code_generation)
if mem_type in delayed_relocate and delayed_relocate[mem_type]:
code_generation_delayed_relocate = generate_memcpy_code(mem_type,
list_of_sections,
code_generation_delayed_relocate)
else:
code_generation = generate_memcpy_code(mem_type,
list_of_sections, code_generation)


dump_header_file(args.output_code, code_generation)
dump_header_file(args.output_code_delayed_relocation, code_generation_delayed_relocate, "_delayed")


if __name__ == '__main__':
Expand Down
Loading