Skip to content
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

code_relocation: Add option to specify load memory segment #76513

Open
wants to merge 2 commits 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
10 changes: 7 additions & 3 deletions cmake/modules/extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1388,9 +1388,10 @@ endmacro()
# - NOKEEP: suppress the generation of KEEP() statements in the linker script,
# to allow any unused code in the given files/library to be discarded.
# - PHDR [program_header]: add program header. Used on Xtensa platforms.
# - LMEM [load_memory]: load memory segment
function(zephyr_code_relocate)
set(options NOCOPY NOKEEP)
set(single_args LIBRARY LOCATION PHDR)
set(single_args LIBRARY LOCATION PHDR LMEM)
set(multi_args FILES)
cmake_parse_arguments(CODE_REL "${options}" "${single_args}"
"${multi_args}" ${ARGN})
Expand Down Expand Up @@ -1457,7 +1458,10 @@ function(zephyr_code_relocate)
list(APPEND flag_list NOKEEP)
endif()
if(CODE_REL_PHDR)
set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}")
set(CODE_REL_LOCATION "${CODE_REL_LOCATION}:PHDR=${CODE_REL_PHDR}")
endif()
if(CODE_REL_LMEM)
set(CODE_REL_LOCATION "${CODE_REL_LOCATION}:LMEM=${CODE_REL_LMEM}")
endif()
# We use the "|" character to separate code relocation directives, instead of
# using set_property(APPEND) to produce a ";"-separated CMake list. This way,
Expand All @@ -1467,7 +1471,7 @@ function(zephyr_code_relocate)
PROPERTY COMPILE_DEFINITIONS)
set_property(TARGET code_data_relocation_target
PROPERTY COMPILE_DEFINITIONS
"${code_rel_str}|${CODE_REL_LOCATION}:${flag_list}:${file_list}")
"${code_rel_str}|${CODE_REL_LOCATION}:FLAGS=${flag_list}:FILES=${file_list}")
endfunction()

# Usage:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ zephyr_code_relocate(FILES src/ext_code.c LOCATION RAM_DATA)

# sram_code instead runs entirely from SRAM after being copied there.
zephyr_code_relocate(FILES src/sram_code.c LOCATION RAM)

# sram_code_from_extflash instead runs entirely from SRAM after being copied there from extflash
zephyr_code_relocate(FILES src/sram_code_from_extflash.c LOCATION RAM LMEM EXTFLASH)
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ void disable_mpu_rasr_xn(void)

extern void function_in_ext_flash(void);
extern void function_in_sram(void);
extern void function_in_sram_from_extflash(void);

int main(void)
{
Expand All @@ -52,6 +53,7 @@ int main(void)

function_in_ext_flash();
function_in_sram();
function_in_sram_from_extflash();

printk("Hello World! %s\n", CONFIG_BOARD);
return 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2022 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

void function_in_sram_from_extflash(void)
{
printk("Address of %s %p\n", __func__, &function_in_sram_from_extflash);
}
69 changes: 39 additions & 30 deletions scripts/build/gen_relocate_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@

Example of such a string would be::

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
SRAM2:FLAGS=COPY:FILES=/home/xyz/zephyr/samples/hello_world/src/main.c,\
SRAM1:FLAGS=COPY:FILES=/home/xyz/zephyr/samples/hello_world/src/main2.c, \
FLASH2:FLAGS=NOCOPY:FILES=/home/xyz/zephyr/samples/hello_world/src/main3.c

One can also specify the program header for a given memory region:

SRAM2\\ :phdr0:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c
SRAM2:PHDR=phdr0:FLAGS=COPY:FILES=/home/xyz/zephyr/samples/hello_world/src/main.c

To invoke this script::

Expand Down Expand Up @@ -113,7 +113,7 @@ class OutputSection(NamedTuple):

LOAD_ADDRESS_LOCATION_FLASH = """
#ifdef CONFIG_XIP
GROUP_DATA_LINK_IN({0}, ROMABLE_REGION)
GROUP_DATA_LINK_IN({0}, {1})
#else
GROUP_DATA_LINK_IN({0}, {0})
#endif
Expand Down Expand Up @@ -332,18 +332,23 @@ def add_phdr(memory_type, phdrs):
return f'{memory_type} {phdrs[memory_type] if memory_type in phdrs else ""}'


def add_lmem(memory_type, lmems):
return f'{lmems[memory_type] if memory_type in lmems else "ROMABLE_REGION"}'


def string_create_helper(
kind: SectionKind,
memory_type,
full_list_of_sections: 'dict[SectionKind, list[OutputSection]]',
load_address_in_flash,
is_copy,
phdrs
phdrs,
lmems
):
linker_string = ''
if load_address_in_flash:
if is_copy:
load_address_string = LOAD_ADDRESS_LOCATION_FLASH.format(add_phdr(memory_type, phdrs))
load_address_string = LOAD_ADDRESS_LOCATION_FLASH.format(add_phdr(memory_type, phdrs), add_lmem(memory_type, lmems))
else:
load_address_string = LOAD_ADDRESS_LOCATION_FLASH_NOCOPY.format(add_phdr(memory_type, phdrs))
else:
Expand Down Expand Up @@ -377,7 +382,7 @@ def string_create_helper(


def generate_linker_script(linker_file, sram_data_linker_file, sram_bss_linker_file,
complete_list_of_sections, phdrs):
complete_list_of_sections, phdrs, lmems):
gen_string = ''
gen_string_sram_data = ''
gen_string_sram_bss = ''
Expand All @@ -391,19 +396,19 @@ def generate_linker_script(linker_file, sram_data_linker_file, sram_bss_linker_f
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(SectionKind.LITERAL, memory_type, full_list_of_sections, 1, is_copy, phdrs)
gen_string += string_create_helper(SectionKind.TEXT, memory_type, full_list_of_sections, 1, is_copy, phdrs)
gen_string += string_create_helper(SectionKind.RODATA, memory_type, full_list_of_sections, 1, is_copy, phdrs)
gen_string += string_create_helper(SectionKind.LITERAL, memory_type, full_list_of_sections, 1, is_copy, phdrs, lmems)
gen_string += string_create_helper(SectionKind.TEXT, memory_type, full_list_of_sections, 1, is_copy, phdrs, lmems)
gen_string += string_create_helper(SectionKind.RODATA, memory_type, full_list_of_sections, 1, is_copy, phdrs, lmems)

if region_is_default_ram(memory_type) and is_copy:
gen_string += MPU_RO_REGION_END.format(memory_type.lower())

if region_is_default_ram(memory_type):
gen_string_sram_data += string_create_helper(SectionKind.DATA, memory_type, full_list_of_sections, 1, 1, phdrs)
gen_string_sram_bss += string_create_helper(SectionKind.BSS, memory_type, full_list_of_sections, 0, 1, phdrs)
gen_string_sram_data += string_create_helper(SectionKind.DATA, memory_type, full_list_of_sections, 1, 1, phdrs, lmems)
gen_string_sram_bss += string_create_helper(SectionKind.BSS, memory_type, full_list_of_sections, 0, 1, phdrs, lmems)
else:
gen_string += string_create_helper(SectionKind.DATA, memory_type, full_list_of_sections, 1, 1, phdrs)
gen_string += string_create_helper(SectionKind.BSS, memory_type, full_list_of_sections, 0, 1, phdrs)
gen_string += string_create_helper(SectionKind.DATA, memory_type, full_list_of_sections, 1, 1, phdrs, lmems)
gen_string += string_create_helper(SectionKind.BSS, memory_type, full_list_of_sections, 0, 1, phdrs, lmems)

# finally writing to the linker file
with open(linker_file, "w") as file_desc:
Expand Down Expand Up @@ -501,22 +506,21 @@ def get_obj_filename(searchpath, filename):


# Extracts all possible components for the input string:
# <mem_region>[\ :program_header]:<flag_1>[;<flag_2>...]:<file_1>[;<file_2>...]
# Returns a 4-tuple with them: (mem_region, program_header, flags, files)
# <mem_region>[:PHDR=program_header][:LMEM=load_memory]:FLAGS=<flag_1>[;<flag_2>...]:FILES=<file_1>[;<file_2>...]
# Returns a 5-tuple with them: (mem_region, program_header, load_mem, flags, files)
# If no `program_header` is defined, returns an empty string
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess a line similar If no program_header is needed for `load_memory.

def parse_input_string(line):
# Be careful when splitting by : to avoid breaking absolute paths on Windows
mem_region, rest = line.split(':', 1)

phdr = ''
if mem_region.endswith(' '):
mem_region = mem_region.rstrip()
phdr, rest = rest.split(':', 1)
line_split = line.split(':')
arg_dict = {i.split('=')[0]: i.split('=')[1] for i in line_split[1:]}
Comment on lines +514 to +515
Copy link
Collaborator

Choose a reason for hiding this comment

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

afaict this breaks on Windows where paths contains :, such as c:/.

Please also take a look at this comment: #74402 (comment)

Perhaps you didn't notice the comment you removed here:

# Be careful when splitting by : to avoid breaking absolute paths on Windows


# Split lists by semicolons, in part to support generator expressions
flag_list, file_list = (lst.split(';') for lst in rest.split(':', 1))
mem_region = line_split[0]
phdr = arg_dict.get('PHDR', '')
lmem = arg_dict.get('LMEM', '')
flag_list = arg_dict.get('FLAGS', '').split(';')
file_list = arg_dict.get('FILES', '').split(';')

return mem_region, phdr, flag_list, file_list
return mem_region, phdr, lmem, flag_list, file_list


# Create a dict with key as memory type and files as a list of values.
Expand All @@ -525,6 +529,7 @@ def create_dict_wrt_mem():
# need to support wild card *
rel_dict = dict()
phdrs = dict()
lmems = dict()

input_rel_dict = args.input_rel_dict.read()
if input_rel_dict == '':
Expand All @@ -533,12 +538,16 @@ def create_dict_wrt_mem():
if ':' not in line:
continue

mem_region, phdr, flag_list, file_list = parse_input_string(line)
mem_region, phdr, lmem, flag_list, file_list = parse_input_string(line)

# Handle any program header
if phdr != '':
phdrs[mem_region] = f':{phdr}'

# Handle any load memory
if lmem != '':
lmems[mem_region.split("_")[0]] = f'{lmem}'

file_name_list = []
# Use glob matching on each file in the list
for file_glob in file_list:
Expand All @@ -563,7 +572,7 @@ def create_dict_wrt_mem():
else:
rel_dict[mem_region] = file_name_list

return rel_dict, phdrs
return rel_dict, phdrs, lmems


def main():
Expand All @@ -574,7 +583,7 @@ def main():
linker_file = args.output
sram_data_linker_file = args.output_sram_data
sram_bss_linker_file = args.output_sram_bss
rel_dict, phdrs = create_dict_wrt_mem()
rel_dict, phdrs, lmems = create_dict_wrt_mem()
complete_list_of_sections: 'dict[MemoryRegion, dict[SectionKind, list[OutputSection]]]' \
= defaultdict(lambda: defaultdict(list))

Expand Down Expand Up @@ -603,7 +612,7 @@ def main():
complete_list_of_sections[region][category].extend(sections)

generate_linker_script(linker_file, sram_data_linker_file,
sram_bss_linker_file, complete_list_of_sections, phdrs)
sram_bss_linker_file, complete_list_of_sections, phdrs, lmems)

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