diff --git a/CMakeLists.txt b/CMakeLists.txt index e96fa75efee..2d1807cba91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,6 +355,7 @@ endif() # Declare MPU userspace dependencies before the linker scripts to make # sure the order of dependencies are met if(CONFIG_USERSPACE) + add_custom_target(app_smem) set(APP_SMEM_ALIGNED_DEP app_smem_aligned_linker) set(APP_SMEM_UNALIGNED_DEP app_smem_unaligned_linker) endif() @@ -985,18 +986,42 @@ toolchain_ld_configure_files() if(CONFIG_USERSPACE) set(APP_SMEM_ALIGNED_LD "${PROJECT_BINARY_DIR}/include/generated/app_smem_aligned.ld") set(APP_SMEM_UNALIGNED_LD "${PROJECT_BINARY_DIR}/include/generated/app_smem_unaligned.ld") + + if(CONFIG_LINKER_USE_PINNED_SECTION) + set(APP_SMEM_PINNED_ALIGNED_LD + "${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned_aligned.ld") + set(APP_SMEM_PINNED_UNALIGNED_LD + "${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned_unaligned.ld") + + if(NOT CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT) + # The libc partition may hold symbols that are required during boot process, + # for example, stack guard (if enabled). So the libc partition must be pinned + # if not sections are in physical memory at boot, as the paging mechanism is + # only initialized post-kernel. + set_property(TARGET app_smem APPEND PROPERTY pinned_partitions "z_libc_partition") + endif() + + get_property(APP_SMEM_PINNED_PARTITION_LIST TARGET app_smem PROPERTY pinned_partitions) + if(APP_SMEM_PINNED_PARTITION_LIST) + list(JOIN APP_SMEM_PINNED_PARTITION_LIST "," APP_SMEM_PINNED_PARTITION_LIST_ARG_CSL) + set(APP_SMEM_PINNED_PARTITION_LIST_ARG "--pinpartitions=${APP_SMEM_PINNED_PARTITION_LIST_ARG_CSL}") + endif() + endif() + set(OBJ_FILE_DIR "${PROJECT_BINARY_DIR}/../") add_custom_target( ${APP_SMEM_ALIGNED_DEP} DEPENDS ${APP_SMEM_ALIGNED_LD} + ${APP_SMEM_PINNED_ALIGNED_LD} ) add_custom_target( ${APP_SMEM_UNALIGNED_DEP} DEPENDS ${APP_SMEM_UNALIGNED_LD} + ${APP_SMEM_PINNED_UNALIGNED_LD} ) if(CONFIG_NEWLIB_LIBC) @@ -1007,11 +1032,13 @@ if(CONFIG_USERSPACE) endif() add_custom_command( - OUTPUT ${APP_SMEM_UNALIGNED_LD} + OUTPUT ${APP_SMEM_UNALIGNED_LD} ${APP_SMEM_PINNED_UNALIGNED_LD} COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/gen_app_partitions.py -d ${OBJ_FILE_DIR} -o ${APP_SMEM_UNALIGNED_LD} + $<$:--pinoutput=${APP_SMEM_PINNED_UNALIGNED_LD}> + ${APP_SMEM_PINNED_PARTITION_LIST_ARG} ${NEWLIB_PART} $ $<$:--verbose> @@ -1029,6 +1056,7 @@ if(CONFIG_USERSPACE) ${CODE_RELOCATION_DEP} ${APP_SMEM_UNALIGNED_DEP} ${APP_SMEM_UNALIGNED_LD} + ${APP_SMEM_PINNED_UNALIGNED_LD} zephyr_generated_headers ) @@ -1061,11 +1089,13 @@ if(CONFIG_USERSPACE) add_dependencies( app_smem_unaligned_prebuilt linker_app_smem_unaligned_script ${OFFSETS_LIB}) add_custom_command( - OUTPUT ${APP_SMEM_ALIGNED_LD} + OUTPUT ${APP_SMEM_ALIGNED_LD} ${APP_SMEM_PINNED_ALIGNED_LD} COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/gen_app_partitions.py -e $ -o ${APP_SMEM_ALIGNED_LD} + $<$:--pinoutput=${APP_SMEM_PINNED_ALIGNED_LD}> + ${APP_SMEM_PINNED_PARTITION_LIST_ARG} ${NEWLIB_PART} $ $<$:--verbose> diff --git a/cmake/linker/ld/target_configure.cmake b/cmake/linker/ld/target_configure.cmake index e088c1ff24c..52801a76751 100644 --- a/cmake/linker/ld/target_configure.cmake +++ b/cmake/linker/ld/target_configure.cmake @@ -18,4 +18,18 @@ macro(toolchain_ld_configure_files) configure_file( ${ZEPHYR_BASE}/include/linker/app_smem_unaligned.ld ${PROJECT_BINARY_DIR}/include/generated/app_smem_unaligned.ld) + + if(CONFIG_LINKER_USE_PINNED_SECTION) + configure_file( + ${ZEPHYR_BASE}/include/linker/app_smem_pinned.ld + ${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned.ld) + + configure_file( + ${ZEPHYR_BASE}/include/linker/app_smem_pinned_aligned.ld + ${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned_aligned.ld) + + configure_file( + ${ZEPHYR_BASE}/include/linker/app_smem_pinned_unaligned.ld + ${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned_unaligned.ld) + endif() endmacro() diff --git a/include/linker/app_smem_pinned.ld b/include/linker/app_smem_pinned.ld new file mode 100644 index 00000000000..0f892f0215b --- /dev/null +++ b/include/linker/app_smem_pinned.ld @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This hackish way of including files is due to CMake issues: + * https://gitlab.kitware.com/cmake/cmake/issues/11985 + * https://gitlab.kitware.com/cmake/cmake/issues/13718 + * + * When using the "Unix Makefiles" generator, CMake simply + * greps for "#include" to generate dependency list. + * So if doing it normally, both files are being included + * in the dependency list. This creates weird dependency + * issue: + * + * 1. Using A.ld to create a linker script A.cmd. + * 2. Using A.cmd to generate A_prebuilt.elf. + * 3. Using A_prebuilt.elf to create B.ld. + * 4. Creating B.cmd with B.ld. + * 5. Creating B_prebuilt.elf using B.cmd. + * + * Since the dependency list of A.cmd contains both + * A.ld and B.ld, when make is invoked again, B.ld + * is newer than A.cmd so everything from this point on + * gets rebuilt. In order to break this cycle, this + * hackish needs to be used since CMake does not parse + * macros, and thus these will not appear in + * the dependency list. The dependencies should then be + * put in CMakeLists.txt instead. + * + * Note: Ninja generator does not suffer from this issue. + */ +#ifdef LINKER_APP_SMEM_UNALIGNED +#define APP_SMEM_LD +#else +#define APP_SMEM_LD +#endif + +#include APP_SMEM_LD +#undef APP_SMEM_LD diff --git a/include/linker/app_smem_pinned_aligned.ld b/include/linker/app_smem_pinned_aligned.ld new file mode 100644 index 00000000000..be6a586656c --- /dev/null +++ b/include/linker/app_smem_pinned_aligned.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2021 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Empty file */ diff --git a/include/linker/app_smem_pinned_unaligned.ld b/include/linker/app_smem_pinned_unaligned.ld new file mode 100644 index 00000000000..524fc468901 --- /dev/null +++ b/include/linker/app_smem_pinned_unaligned.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2021 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Empty file */ diff --git a/include/linker/linker-defs.h b/include/linker/linker-defs.h index 5cb8d3fe6fa..7efab81f38c 100644 --- a/include/linker/linker-defs.h +++ b/include/linker/linker-defs.h @@ -197,6 +197,13 @@ extern char _app_smem_size[]; extern char _app_smem_rom_start[]; extern char _app_smem_num_words[]; +#ifdef CONFIG_LINKER_USE_PINNED_SECTION +extern char _app_smem_pinned_start[]; +extern char _app_smem_pinned_end[]; +extern char _app_smem_pinned_size[]; +extern char _app_smem_pinned_num_words[]; +#endif + /* Memory owned by the kernel. Start and end will be aligned for memory * management/protection hardware for the target architecture. * diff --git a/include/linker/sections.h b/include/linker/sections.h index f172cfb9089..49cf558776a 100644 --- a/include/linker/sections.h +++ b/include/linker/sections.h @@ -28,6 +28,8 @@ #define _APP_BSS_SECTION_NAME app_bss #define _APP_NOINIT_SECTION_NAME app_noinit +#define _APP_SMEM_PINNED_SECTION_NAME app_smem_pinned + #define _UNDEFINED_SECTION_NAME undefined /* Interrupts */ diff --git a/kernel/userspace.c b/kernel/userspace.c index 84550863111..bd8a83bbc94 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef Z_LIBC_PARTITION_EXISTS K_APPMEM_PARTITION_DEFINE(z_libc_partition); @@ -859,7 +860,29 @@ static int app_shmem_bss_zero(const struct device *unused) region = (struct z_app_region *)&__app_shmem_regions_start; for ( ; region < end; region++) { - (void)memset(region->bss_start, 0, region->bss_size); +#if defined(CONFIG_DEMAND_PAGING) && !defined(CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT) + /* When BSS sections are not present at boot, we need to wait for + * paging mechanism to be initialized before we can zero out BSS. + */ + extern bool z_sys_post_kernel; + bool do_clear = z_sys_post_kernel; + + /* During pre-kernel init, z_sys_post_kernel == false, but + * with pinned rodata region, so clear. Otherwise skip. + * In post-kernel init, z_sys_post_kernel == true, + * skip those in pinned rodata region as they have already + * been cleared and possibly already in use. Otherwise clear. + */ + if (((uint8_t *)region->bss_start >= (uint8_t *)_app_smem_pinned_start) && + ((uint8_t *)region->bss_start < (uint8_t *)_app_smem_pinned_end)) { + do_clear = !do_clear; + } + + if (do_clear) +#endif /* CONFIG_DEMAND_PAGING && !CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT */ + { + (void)memset(region->bss_start, 0, region->bss_size); + } } return 0; @@ -867,6 +890,13 @@ static int app_shmem_bss_zero(const struct device *unused) SYS_INIT(app_shmem_bss_zero, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#if defined(CONFIG_DEMAND_PAGING) && !defined(CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT) +/* When BSS sections are not present at boot, we need to wait for + * paging mechanism to be initialized before we can zero out BSS. + */ +SYS_INIT(app_shmem_bss_zero, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif /* CONFIG_DEMAND_PAGING && !CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT */ + /* * Default handlers if otherwise unimplemented */ diff --git a/scripts/gen_app_partitions.py b/scripts/gen_app_partitions.py index 38758f1a459..9cb903880ef 100644 --- a/scripts/gen_app_partitions.py +++ b/scripts/gen_app_partitions.py @@ -75,16 +75,24 @@ footer_template = """ """ linker_start_seq = """ - SECTION_PROLOGUE(_APP_SMEM_SECTION_NAME,,) - { + SECTION_PROLOGUE(_APP_SMEM{1}_SECTION_NAME,,) + {{ APP_SHARED_ALIGN; - _app_smem_start = .; + _app_smem{0}_start = .; """ linker_end_seq = """ APP_SHARED_ALIGN; - _app_smem_end = .; - } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + _app_smem{0}_end = .; + }} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) +""" + +empty_app_smem = """ + SECTION_PROLOGUE(_APP_SMEM{1}_SECTION_NAME,,) + {{ + _app_smem{0}_start = .; + _app_smem{0}_end = .; + }} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) """ size_cal_string = """ @@ -159,23 +167,29 @@ def parse_elf_file(partitions): partitions[partition_name][SZ] += size -def generate_final_linker(linker_file, partitions): - string = linker_start_seq - size_string = '' - for partition, item in partitions.items(): - string += data_template.format(partition) - if LIB in item: - for lib in item[LIB]: - string += library_data_template.format(lib) - string += bss_template.format(partition) - if LIB in item: - for lib in item[LIB]: - string += library_bss_template.format(lib) - string += footer_template.format(partition) - size_string += size_cal_string.format(partition) +def generate_final_linker(linker_file, partitions, lnkr_sect=""): + string = "" + + if len(partitions) > 0: + string = linker_start_seq.format(lnkr_sect, lnkr_sect.upper()) + size_string = '' + for partition, item in partitions.items(): + string += data_template.format(partition) + if LIB in item: + for lib in item[LIB]: + string += library_data_template.format(lib) + string += bss_template.format(partition, lnkr_sect) + if LIB in item: + for lib in item[LIB]: + string += library_bss_template.format(lib) + string += footer_template.format(partition) + size_string += size_cal_string.format(partition) + + string += linker_end_seq.format(lnkr_sect) + string += size_string + else: + string = empty_app_smem.format(lnkr_sect, lnkr_sect.upper()) - string += linker_end_seq - string += size_string with open(linker_file, "w") as fw: fw.write(string) @@ -196,6 +210,10 @@ def parse_args(): parser.add_argument("-l", "--library", nargs=2, action="append", default=[], metavar=("LIBRARY", "PARTITION"), help="Include globals for a particular library or object filename into a designated partition") + parser.add_argument("--pinoutput", required=False, + help="Output ld file for pinned sections") + parser.add_argument("--pinpartitions", action="store", required=False, default="", + help="Comma separated names of partitions to be pinned in physical memory") args = parser.parse_args() @@ -220,11 +238,20 @@ def main(): else: partitions[ptn][LIB].append(lib) + if args.pinoutput: + pin_part_names = args.pinpartitions.split(',') + + generic_partitions = {key: value for key, value in partitions.items() + if key not in pin_part_names} + pinned_partitions = {key: value for key, value in partitions.items() + if key in pin_part_names} + else: + generic_partitions = partitions # Sample partitions.items() list before sorting: # [ ('part1', {'size': 64}), ('part3', {'size': 64}, ... # ('part0', {'size': 334}) ] - decreasing_tuples = sorted(partitions.items(), + decreasing_tuples = sorted(generic_partitions.items(), key=lambda x: (x[1][SZ], x[0]), reverse=True) partsorted = OrderedDict(decreasing_tuples) @@ -237,6 +264,20 @@ def main(): partsorted[key][SZ], partsorted[key][SRC])) + if args.pinoutput: + decreasing_tuples = sorted(pinned_partitions.items(), + key=lambda x: (x[1][SZ], x[0]), reverse=True) + + partsorted = OrderedDict(decreasing_tuples) + + generate_final_linker(args.pinoutput, partsorted, lnkr_sect="_pinned") + if args.verbose: + print("Pinned partitions retrieved:") + for key in partsorted: + print(" {0}: size {1}: {2}".format(key, + partsorted[key][SZ], + partsorted[key][SRC])) + if __name__ == '__main__': main() diff --git a/scripts/gen_kobject_list.py b/scripts/gen_kobject_list.py index 93f2ed80e80..b9b0ca1a346 100755 --- a/scripts/gen_kobject_list.py +++ b/scripts/gen_kobject_list.py @@ -514,6 +514,14 @@ def find_kobjects(elf, syms): app_smem_start = syms["_app_smem_start"] app_smem_end = syms["_app_smem_end"] + + if "CONFIG_LINKER_USE_PINNED_SECTION" in syms and "_app_smem_pinned_start" in syms: + app_smem_pinned_start = syms["_app_smem_pinned_start"] + app_smem_pinned_end = syms["_app_smem_pinned_end"] + else: + app_smem_pinned_start = app_smem_start + app_smem_pinned_end = app_smem_end + user_stack_start = syms["z_user_stacks_start"] user_stack_end = syms["z_user_stacks_end"] @@ -630,7 +638,9 @@ def find_kobjects(elf, syms): continue _, user_ram_allowed, _ = kobjects[ko.type_obj.name] - if not user_ram_allowed and app_smem_start <= addr < app_smem_end: + if (not user_ram_allowed and + ((app_smem_start <= addr < app_smem_end) + or (app_smem_pinned_start <= addr < app_smem_pinned_end))): debug("object '%s' found in invalid location %s" % (ko.type_obj.name, hex(addr))) continue