From 11171699801a8f20be3d84fdf2548eb92ab8a443 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 18 Mar 2021 14:00:07 -0700 Subject: [PATCH] kernel: generate placeholders for kobj tables before final build Due to the use of gperf to generate hash table for kobjects, the addresses of these kobjects cannot change during the last few phases of linking (especially between zephyr_prebuilt.elf and zephyr.elf). Because of this, the gperf generated data needs to be placed at the end of memory to avoid pushing symbols around in memory. This prevents moving these generated blocks to earlier sections, for example, pinned data section needed for demand paging. So create placeholders for use in intermediate linking to reserve space for these generated blocks. Due to uncertainty on the size of these blocks, more space is being reserved which could result in wasted space. Though, this retains the use of hash table for faster lookup. Signed-off-by: Daniel Leung --- CMakeLists.txt | 132 +++++++++++++++++ CODEOWNERS | 1 + arch/Kconfig | 24 ++- include/arch/arc/v2/linker.ld | 2 +- .../arm/aarch32/cortex_a_r/scripts/linker.ld | 2 +- .../arm/aarch32/cortex_m/scripts/linker.ld | 2 +- include/arch/arm64/scripts/linker.ld | 2 +- include/arch/riscv/common/linker.ld | 2 +- include/arch/x86/ia32/linker.ld | 2 +- include/arch/x86/intel64/linker.ld | 4 +- include/linker/common-noinit.ld | 2 + include/linker/kobject-data.ld | 75 ++++++++++ include/linker/kobject-priv-stacks.ld | 58 ++++++++ include/linker/kobject-rom.ld | 56 ++++++- include/linker/kobject.ld | 52 ------- kernel/include/kernel_internal.h | 3 - kernel/init.c | 3 - kernel/mmu.c | 24 --- scripts/gen_kobject_placeholders.py | 139 ++++++++++++++++++ 19 files changed, 488 insertions(+), 97 deletions(-) create mode 100644 include/linker/kobject-data.ld create mode 100644 include/linker/kobject-priv-stacks.ld delete mode 100644 include/linker/kobject.ld create mode 100755 scripts/gen_kobject_placeholders.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e1d3df2ab5..f46dfe572a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -350,6 +350,10 @@ if(CONFIG_USERSPACE) set(APP_SMEM_UNALIGNED_DEP app_smem_unaligned_linker) endif() +if(CONFIG_USERSPACE) + set(KOBJECT_LINKER_DEP kobject_linker) +endif() + get_property(TOPT GLOBAL PROPERTY TOPT) set_ifndef( TOPT -Wl,-T) # clang doesn't pick -T for some reason and complains, # while -Wl,-T works for both, gcc and clang @@ -847,6 +851,7 @@ if(CONFIG_USERSPACE) COMMAND ${GPERF} --output-file ${KOBJECT_HASH_OUTPUT_SRC_PRE} + --multiple-iterations 10 ${KOBJECT_HASH_LIST} DEPENDS kobj_hash_list ${KOBJECT_HASH_LIST} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} @@ -1062,10 +1067,137 @@ if(CONFIG_USERSPACE) ) endif() +if(CONFIG_USERSPACE) + # This CONFIG_USERSPACE block is to create place holders to reserve space + # for the gperf generated structures for zephyr_prebuilt.elf. + # These place holders are there so that the placement of kobjects would be + # the same between linking zephyr_prebuilt.elf and zephyr.elf, as + # the gperf hash table is hashed on the addresses of kobjects. + # The placeholders are generated from app_smem_unaligned_prebuilt.elf. + + set(KOBJECT_PREBUILT_HASH_LIST kobject_prebuilt_hash.gperf) + set(KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE kobject_prebuilt_hash_preprocessed.c) + set(KOBJECT_PREBUILT_HASH_OUTPUT_SRC kobject_prebuilt_hash.c) + set(KOBJECT_PREBUILT_HASH_OUTPUT_OBJ kobject_prebuilt_hash.c.obj) + + add_custom_command( + OUTPUT ${KOBJECT_PREBUILT_HASH_LIST} + COMMAND + ${PYTHON_EXECUTABLE} + ${GEN_KOBJ_LIST} + --kernel $ + --gperf-output ${KOBJECT_PREBUILT_HASH_LIST} + ${gen_kobject_list_include_args} + $<$:--verbose> + DEPENDS + app_smem_unaligned_prebuilt + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + add_custom_target( + kobj_prebuilt_hash_list + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_PREBUILT_HASH_LIST} + ) + + add_custom_command( + OUTPUT ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE} + COMMAND + ${GPERF} + --output-file ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE} + --multiple-iterations 10 + ${KOBJECT_PREBUILT_HASH_LIST} + DEPENDS kobj_prebuilt_hash_list ${KOBJECT_PREBUILT_HASH_LIST} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + add_custom_target( + kobj_prebuilt_hash_output_src_pre + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE} + ) + + add_custom_command( + OUTPUT ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC} + COMMAND + ${PYTHON_EXECUTABLE} + ${PROCESS_GPERF} + -i ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE} + -o ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC} + -p "struct z_object" + $<$:--verbose> + DEPENDS kobj_prebuilt_hash_output_src_pre ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + add_custom_target( + kobj_prebuilt_hash_output_src + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_PREBUILT_HASH_OUTPUT_SRC} + ) + + add_library( + kobj_prebuilt_hash_output_lib + STATIC ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_PREBUILT_HASH_OUTPUT_SRC} + ) + + set_source_files_properties(${KOBJECT_PREBUILT_HASH_OUTPUT_SRC} + PROPERTIES COMPILE_FLAGS + "${NO_COVERAGE_FLAGS} -fno-function-sections -fno-data-sections") + + set_source_files_properties(${KOBJECT_PREBUILT_HASH_OUTPUT_SRC} + PROPERTIES COMPILE_DEFINITIONS "${compile_definitions_interface}") + + add_library(kobj_prebuilt_hash_output_lib_interface INTERFACE) + + target_link_libraries( + kobj_prebuilt_hash_output_lib + kobj_prebuilt_hash_output_lib_interface + ) + + foreach(incl ${include_dir_in_interface}) + target_include_directories( + kobj_prebuilt_hash_output_lib_interface + INTERFACE ${incl} + ) + endforeach() + + foreach(incl ${sys_include_dir_in_interface}) + target_include_directories( + kobj_prebuilt_hash_output_lib_interface + SYSTEM INTERFACE ${incl} + ) + endforeach() + + set( + KOBJECT_PREBUILT_HASH_OUTPUT_OBJ_PATH + ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/kobj_prebuilt_hash_output_lib.dir/${KOBJECT_PREBUILT_HASH_OUTPUT_OBJ} + ) + + set(KOBJECT_LINKER_HEADER_DATA "${PROJECT_BINARY_DIR}/include/generated/linker-kobject-prebuilt-data.h") + + add_custom_command( + OUTPUT ${KOBJECT_LINKER_HEADER_DATA} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/gen_kobject_placeholders.py + --object ${KOBJECT_PREBUILT_HASH_OUTPUT_OBJ_PATH} + --outdir ${PROJECT_BINARY_DIR}/include/generated + --datapct ${CONFIG_KOBJECT_DATA_AREA_RESERVE_EXTRA_PERCENT} + --rodata ${CONFIG_KOBJECT_RODATA_AREA_EXTRA_BYTES} + $<$:--verbose> + DEPENDS + kobj_prebuilt_hash_output_lib + ${KOBJECT_PREBUILT_HASH_OUTPUT_OBJ_PATH} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + + add_custom_target( + ${KOBJECT_LINKER_DEP} + DEPENDS + ${KOBJECT_LINKER_HEADER_DATA} + ) +endif() + configure_linker_script( linker_zephyr_prebuilt.cmd "-DLINKER_ZEPHYR_PREBUILT" ${APP_SMEM_ALIGNED_DEP} + ${KOBJECT_LINKER_DEP} ${CODE_RELOCATION_DEP} zephyr_generated_headers ) diff --git a/CODEOWNERS b/CODEOWNERS index a4271facd73..e81e1dfd38a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -547,6 +547,7 @@ /arch/x86/gen_gdt.py @dcpleung @nashif /arch/x86/gen_idt.py @dcpleung @nashif /scripts/gen_kobject_list.py @dcpleung @nashif +/scripts/gen_kobject_placeholders.py @dcpleung /scripts/gen_syscalls.py @dcpleung @nashif /scripts/list_boards.py @mbolivar-nordic /scripts/net/ @jukkar diff --git a/arch/Kconfig b/arch/Kconfig index 00967ee2a57..3061d82cdbe 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -273,7 +273,7 @@ config PRIVILEGED_STACK_SIZE a multiple of the minimum stack alignment. config KOBJECT_TEXT_AREA - int "Size if kobject text area" + int "Size of kobject text area" default 512 if COVERAGE_GCOV default 512 if NO_OPTIMIZATIONS default 512 if STACK_CANARIES && RISCV @@ -282,6 +282,28 @@ config KOBJECT_TEXT_AREA help Size of kernel object text area. Used in linker script. +config KOBJECT_DATA_AREA_RESERVE_EXTRA_PERCENT + int "Reserve extra kobject data area (in percentage)" + default 100 + depends on ARCH_HAS_USERSPACE + help + Multiplication factor used to calculate the size of placeholder to + reserve space for kobject metadata hash table. The hash table is + generated via gperf is highly dependent on the absolute addresses of + kobjects which might change between prebuilts. To reserve enough + space for the hash table during final linking passes to keep + kobjects in same place, the size of reserved space is calculated + from the first prebuilt plus additional space calculated with + this percentage (of the kobject data area in first prebuilt). + +config KOBJECT_RODATA_AREA_EXTRA_BYTES + int "Reserve extra bytes for kobject rodata area" + default 16 + depends on ARCH_HAS_USERSPACE + help + Reserve a few more bytes for the RODATA region for kobject metadata. + This is to account for the uncertainty of tables generated by gperf. + config GEN_PRIV_STACKS bool help diff --git a/include/arch/arc/v2/linker.ld b/include/arch/arc/v2/linker.ld index e5398952529..25ceca7c995 100644 --- a/include/arch/arc/v2/linker.ld +++ b/include/arch/arc/v2/linker.ld @@ -188,7 +188,7 @@ SECTIONS { __data_rom_start = LOADADDR(_DATA_SECTION_NAME); #include -#include +#include #ifdef __MWDT_LINKER_CMD__ /* TODO: add mwdt specific RAM C++ sections */ diff --git a/include/arch/arm/aarch32/cortex_a_r/scripts/linker.ld b/include/arch/arm/aarch32/cortex_a_r/scripts/linker.ld index def88f5a99b..1501151572d 100644 --- a/include/arch/arm/aarch32/cortex_a_r/scripts/linker.ld +++ b/include/arch/arm/aarch32/cortex_a_r/scripts/linker.ld @@ -295,7 +295,7 @@ SECTIONS __data_rom_start = LOADADDR(_DATA_SECTION_NAME); #include -#include +#include #include __data_ram_end = .; diff --git a/include/arch/arm/aarch32/cortex_m/scripts/linker.ld b/include/arch/arm/aarch32/cortex_m/scripts/linker.ld index d07b7b12617..adf43203116 100644 --- a/include/arch/arm/aarch32/cortex_m/scripts/linker.ld +++ b/include/arch/arm/aarch32/cortex_m/scripts/linker.ld @@ -329,7 +329,7 @@ SECTIONS __data_rom_start = LOADADDR(_DATA_SECTION_NAME); #include -#include +#include #include diff --git a/include/arch/arm64/scripts/linker.ld b/include/arch/arm64/scripts/linker.ld index d9710aa344d..47812a9f979 100644 --- a/include/arch/arm64/scripts/linker.ld +++ b/include/arch/arm64/scripts/linker.ld @@ -271,7 +271,7 @@ SECTIONS __data_rom_start = LOADADDR(_DATA_SECTION_NAME); #include -#include +#include #include __data_ram_end = .; diff --git a/include/arch/riscv/common/linker.ld b/include/arch/riscv/common/linker.ld index 6560e7f9e3e..f5db23cd278 100644 --- a/include/arch/riscv/common/linker.ld +++ b/include/arch/riscv/common/linker.ld @@ -225,7 +225,7 @@ SECTIONS __data_rom_start = LOADADDR(_DATA_SECTION_NAME); #include -#include +#include /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. diff --git a/include/arch/x86/ia32/linker.ld b/include/arch/x86/ia32/linker.ld index 9eba72d0657..d71620f4761 100644 --- a/include/arch/x86/ia32/linker.ld +++ b/include/arch/x86/ia32/linker.ld @@ -336,7 +336,7 @@ SECTIONS #include /* Must be last in RAM */ -#include +#include MMU_PAGE_ALIGN __data_ram_end = .; diff --git a/include/arch/x86/intel64/linker.ld b/include/arch/x86/intel64/linker.ld index 7eb9987544f..e149276b616 100644 --- a/include/arch/x86/intel64/linker.ld +++ b/include/arch/x86/intel64/linker.ld @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Intel Corp. + * Copyright (c) 2019-2021 Intel Corp. * SPDX-License-Identifier: Apache-2.0 */ @@ -185,7 +185,7 @@ SECTIONS #include /* Must be last in RAM */ -#include +#include MMU_PAGE_ALIGN _image_ram_end = .; z_mapped_end = .; diff --git a/include/linker/common-noinit.ld b/include/linker/common-noinit.ld index bf940c8ae68..fba2221162b 100644 --- a/include/linker/common-noinit.ld +++ b/include/linker/common-noinit.ld @@ -24,3 +24,5 @@ SECTION_PROLOGUE(_NOINIT_SECTION_NAME,(NOLOAD),) #include } GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + +#include "kobject-priv-stacks.ld" diff --git a/include/linker/kobject-data.ld b/include/linker/kobject-data.ld new file mode 100644 index 00000000000..bb258158c45 --- /dev/null +++ b/include/linker/kobject-data.ld @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017,2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef CONFIG_USERSPACE + + z_kobject_data_begin = .; + SECTION_DATA_PROLOGUE(kobject_data,,) + { + +#if !defined(LINKER_ZEPHYR_PREBUILT) && \ + !defined(LINKER_ZEPHYR_FINAL) + +#ifdef CONFIG_DYNAMIC_OBJECTS + PROVIDE(_thread_idx_map = .); + . += CONFIG_MAX_THREAD_BYTES; +#endif + +#endif /* !LINKER_ZEPHYR_PREBUILT && !LINKER_ZEPHYR_FINAL */ + + /* During LINKER_KOBJECT_PREBUILT and LINKER_ZEPHYR_PREBUILT, + * space needs to be reserved for the rodata that will be + * produced by gperf during the final stages of linking. + * The alignment and size are produced by + * scripts/gen_kobject_placeholders.py. These are here + * so the addresses to kobjects would remain the same + * during the final stages of linking (LINKER_ZEPHYR_FINAL). + */ + +#if defined(LINKER_ZEPHYR_PREBUILT) +#include + +#ifdef CONFIG_DYNAMIC_OBJECTS + /* This is produced by gperf. Put a place holder here + * to avoid compilation error. + */ + PROVIDE(_thread_idx_map = .); +#endif +#ifdef KOBJECT_DATA_ALIGN + . = ALIGN(KOBJECT_DATA_ALIGN); + . += KOBJECT_DATA_SZ; +#endif +#endif /* LINKER_ZEPHYR_PREBUILT */ + +#if defined(LINKER_ZEPHYR_FINAL) +#include +#ifdef KOBJECT_DATA_ALIGN + . = ALIGN(KOBJECT_DATA_ALIGN); + + _kobject_data_area_start = .; +#endif + + *(".kobject_data.data*") + +#ifdef KOBJECT_DATA_ALIGN + _kobject_data_area_end = .; + _kobject_data_area_used = _kobject_data_area_end - _kobject_data_area_start; + + ASSERT(_kobject_data_area_used <= KOBJECT_DATA_SZ, +"scripts/gen_kobject_placeholders.py did not reserve enough space \ +for kobject data." + ); + + /* Padding is needed to preserve kobject addresses + * if we have reserved more space than needed. + */ + . = MAX(., _kobject_data_area_start + KOBJECT_DATA_SZ); +#endif /* KOBJECT_DATA_ALIGN */ +#endif /* LINKER_ZEPHYR_FINAL */ + + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + +#endif /* CONFIG_USERSPACE */ diff --git a/include/linker/kobject-priv-stacks.ld b/include/linker/kobject-priv-stacks.ld new file mode 100644 index 00000000000..94861db22cd --- /dev/null +++ b/include/linker/kobject-priv-stacks.ld @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017,2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef CONFIG_USERSPACE +#ifdef CONFIG_GEN_PRIV_STACKS + SECTION_DATA_PROLOGUE(priv_stacks_noinit,,) + { + z_priv_stacks_ram_start = .; + + /* During LINKER_KOBJECT_PREBUILT and LINKER_ZEPHYR_PREBUILT, + * space needs to be reserved for the rodata that will be + * produced by gperf during the final stages of linking. + * The alignment and size are produced by + * scripts/gen_kobject_placeholders.py. These are here + * so the addresses to kobjects would remain the same + * during the final stages of linking (LINKER_ZEPHYR_FINAL). + */ + +#if defined(LINKER_ZEPHYR_PREBUILT) +#include +#ifdef KOBJECT_PRIV_STACKS_ALIGN + . = ALIGN(KOBJECT_PRIV_STACKS_ALIGN); + . += KOBJECT_PRIV_STACKS_SZ; +#endif +#endif /* LINKER_ZEPHYR_PREBUILT */ + +#if defined(LINKER_ZEPHYR_FINAL) +#include +#ifdef KOBJECT_PRIV_STACKS_ALIGN + . = ALIGN(KOBJECT_PRIV_STACKS_ALIGN); +#endif + *(".priv_stacks.noinit") +#endif /* LINKER_ZEPHYR_FINAL */ + + z_priv_stacks_ram_end = .; + +#if defined(LINKER_ZEPHYR_FINAL) +#ifdef KOBJECT_PRIV_STACKS_ALIGN + z_priv_stacks_ram_used = z_priv_stacks_ram_end - z_priv_stacks_ram_start; + + ASSERT(z_priv_stacks_ram_used <= KOBJECT_PRIV_STACKS_SZ, +"scripts/gen_kobject_placeholders.py did not reserve enough space \ +for priviledged stacks." + ); + + /* Padding is needed to preserve kobject addresses + * if we have reserved more space than needed. + */ + . = MAX(., z_priv_stacks_ram_start + KOBJECT_PRIV_STACKS_SZ); +#endif /* KOBJECT_PRIV_STACKS_ALIGN */ +#endif /* LINKER_ZEPHYR_FINAL */ + + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) +#endif /* CONFIG_GEN_PRIV_STACKS */ +#endif /* CONFIG_USERSPACE */ diff --git a/include/linker/kobject-rom.ld b/include/linker/kobject-rom.ld index 66f5a4ec300..4b03bc8565c 100644 --- a/include/linker/kobject-rom.ld +++ b/include/linker/kobject-rom.ld @@ -1,13 +1,57 @@ /* - * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2017,2021 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #ifdef CONFIG_USERSPACE - /* Kept in RAM on non-XIP */ -#ifdef CONFIG_XIP - *(".kobject_data.rodata*") -#endif -#endif /* CONFIG_USERSPACE */ + /* During LINKER_KOBJECT_PREBUILT and LINKER_ZEPHYR_PREBUILT, + * space needs to be reserved for the rodata that will be + * produced by gperf during the final stages of linking. + * The alignment and size are produced by + * scripts/gen_kobject_placeholders.py. These are here + * so the addresses to kobjects would remain the same + * during the final stages of linking (LINKER_ZEPHYR_FINAL). + */ + +#if defined(LINKER_ZEPHYR_PREBUILT) +#include +#ifdef KOBJECT_RODATA_ALIGN + . = ALIGN(KOBJECT_RODATA_ALIGN); + + _kobject_rodata_area_start = .; + + . += KOBJECT_RODATA_SZ; + + _kobject_rodata_area_end = .; +#endif +#endif /* LINKER_ZEPHYR_PREBUILT */ + +#if defined(LINKER_ZEPHYR_FINAL) +#include +#ifdef KOBJECT_RODATA_ALIGN + . = ALIGN(KOBJECT_RODATA_ALIGN); + + _kobject_rodata_area_start = .; +#endif + + *(".kobject_data.rodata*") + +#ifdef KOBJECT_RODATA_ALIGN + _kobject_rodata_area_end = .; + _kobject_rodata_area_used = _kobject_rodata_area_end - _kobject_rodata_area_start; + + ASSERT(_kobject_rodata_area_used <= KOBJECT_RODATA_SZ, +"scripts/gen_kobject_placeholders.py did not reserve enough space \ +for kobject rodata." + ); + + /* Padding is needed to preserve kobject addresses + * if we have reserved more space than needed. + */ + . = MAX(., _kobject_rodata_area_start + KOBJECT_RODATA_SZ); +#endif /* KOBJECT_RODATA_ALIGN */ +#endif /* LINKER_ZEPHYR_FINAL */ + +#endif /* CONFIG_USERSPACE */ diff --git a/include/linker/kobject.ld b/include/linker/kobject.ld deleted file mode 100644 index 114347e690f..00000000000 --- a/include/linker/kobject.ld +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifdef CONFIG_USERSPACE - z_kobject_data_begin = .; - /* Constraints: - * - * - changes to the size of this section between build phases - * *must not* shift the memory address of any kernel obejcts, - * since it contains a hashtable of the memory addresses of those - * kernel objects - * - * - It is OK if this section itself is shifted in between builds; for - * example some arches may precede this section with generated MMU - * page tables which are also unpredictable in size. - * - * The size of the - * gperf tables is both a function of the number of kernel objects, - * *and* the specific memory addresses being hashed. It is not something - * that can be predicted without actually building and compling it. - */ - SECTION_DATA_PROLOGUE(kobject_data,,) - { - *(".kobject_data.data*") - -#ifndef LINKER_ZEPHYR_FINAL -#ifdef CONFIG_DYNAMIC_OBJECTS - PROVIDE(_thread_idx_map = .); - . += CONFIG_MAX_THREAD_BYTES; -#endif -#endif - - /* This is also unpredictable in size, and has the same constraints. - * On XIP systems this will get put at the very end of ROM. - */ -#ifndef CONFIG_XIP - *(".kobject_data.rodata*") -#endif - } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) - -#ifdef CONFIG_GEN_PRIV_STACKS - SECTION_DATA_PROLOGUE(priv_stacks_noinit,,) - { - z_priv_stacks_ram_start = .; - *(".priv_stacks.noinit") - z_priv_stacks_ram_end = .; - } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) -#endif /* CONFIG_GEN_PRIV_STACKS */ -#endif /* CONFIG_USERSPACE */ diff --git a/kernel/include/kernel_internal.h b/kernel/include/kernel_internal.h index d377d736bc8..0eaffbfa161 100644 --- a/kernel/include/kernel_internal.h +++ b/kernel/include/kernel_internal.h @@ -199,9 +199,6 @@ void z_thread_mark_switched_out(void); */ void z_mem_manage_init(void); -/* Workaround for build-time page table mapping of the kernel */ -void z_kernel_map_fixup(void); - #define LOCKED(lck) for (k_spinlock_key_t __i = {}, \ __key = k_spin_lock(lck); \ !__i.key; \ diff --git a/kernel/init.c b/kernel/init.c index 3448dde5584..f7d05e18110 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -382,9 +382,6 @@ FUNC_NORETURN void z_cstart(void) struct k_thread dummy_thread; z_dummy_thread_init(&dummy_thread); -#endif -#if defined(CONFIG_MMU) && defined(CONFIG_USERSPACE) - z_kernel_map_fixup(); #endif /* do any necessary initialization of static devices */ z_device_state_init(); diff --git a/kernel/mmu.c b/kernel/mmu.c index baab6b455d0..85dbdc06ace 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -486,30 +486,6 @@ size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, return addr_offset; } - -#ifdef CONFIG_USERSPACE -void z_kernel_map_fixup(void) -{ - /* XXX: Gperf kernel object data created at build time will not have - * visibility in zephyr_prebuilt.elf. There is a possibility that this - * data would not be memory-mapped if it shifts z_mapped_end between - * builds. Ensure this area is mapped. - * - * A third build phase for page tables would solve this. - */ - uint8_t *kobject_page_begin = - (uint8_t *)ROUND_DOWN((uintptr_t)&z_kobject_data_begin, - CONFIG_MMU_PAGE_SIZE); - size_t kobject_size = (size_t)(Z_KERNEL_VIRT_END - kobject_page_begin); - - if (kobject_size != 0U) { - arch_mem_map(kobject_page_begin, - Z_BOOT_VIRT_TO_PHYS(kobject_page_begin), - kobject_size, K_MEM_PERM_RW | K_MEM_CACHE_WB); - } -} -#endif /* CONFIG_USERSPACE */ - void z_mem_manage_init(void) { uintptr_t phys; diff --git a/scripts/gen_kobject_placeholders.py b/scripts/gen_kobject_placeholders.py new file mode 100755 index 00000000000..bd529bc16cd --- /dev/null +++ b/scripts/gen_kobject_placeholders.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +""" +Process ELF file to generate placeholders for kobject +hash table and lookup functions produced by gperf, +since their sizes depend on how many kobjects have +been declared. The output header files will be used +during linking for intermediate output binaries so +that the addresses of these kobjects would remain +the same during later stages of linking. +""" + +import sys +import argparse +import os +from distutils.version import LooseVersion + +import elftools +from elftools.elf.elffile import ELFFile + + +if LooseVersion(elftools.__version__) < LooseVersion('0.24'): + sys.exit("pyelftools is out of date, need version 0.24 or later") + + +def write_define(out_fp, prefix, name, value): + """Write the #define to output file""" + define_name = f"KOBJECT_{prefix}_{name}" + out_fp.write(f"#ifndef {define_name}\n") + out_fp.write(f"#define {define_name} {value}\n") + out_fp.write("#endif\n\n") + + +def output_simple_header(one_sect): + """Write the header for kobject section""" + + out_fn = os.path.join(args.outdir, + f"linker-kobject-prebuilt-{one_sect['name']}.h") + out_fp = open(out_fn, "w") + + if one_sect['exists']: + align = one_sect['align'] + size = one_sect['size'] + prefix = one_sect['define_prefix'] + + write_define(out_fp, prefix, 'ALIGN', align) + write_define(out_fp, prefix, 'SZ', size) + + out_fp.close() + + +def generate_linker_headers(obj): + """Generate linker header files to be included by the linker script""" + + # Sections we are interested in + sections = { + ".data": { + "name": "data", + "define_prefix": "DATA", + "exists": False, + "multiplier": int(args.datapct) + 100, + }, + ".rodata": { + "name": "rodata", + "define_prefix": "RODATA", + "exists": False, + "extra_bytes": args.rodata, + }, + ".priv_stacks.noinit": { + "name": "priv-stacks", + "define_prefix": "PRIV_STACKS", + "exists": False, + }, + } + + for one_sect in obj.iter_sections(): + # REALLY NEED to match exact type as all other sections + # (symbol, debug, etc.) are descendants where + # isinstance() would match. + if type(one_sect) is not elftools.elf.sections.Section: # pylint: disable=unidiomatic-typecheck + continue + + name = one_sect.name + if name in sections.keys(): + # Need section alignment and size + sections[name]['align'] = one_sect['sh_addralign'] + sections[name]['size'] = one_sect['sh_size'] + sections[name]['exists'] = True + + if "multiplier" in sections[name]: + sections[name]['size'] *= sections[name]['multiplier'] / 100 + sections[name]['size'] = int(sections[name]['size']) + + if "extra_bytes" in sections[name]: + sections[name]['size'] += int(sections[name]['extra_bytes']) + + for one_sect in sections: + output_simple_header(sections[one_sect]) + + +def parse_args(): + """Parse command line arguments""" + global args + + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + + parser.add_argument("--object", required=True, + help="Points to kobject_prebuilt_hash.c.obj") + parser.add_argument("--outdir", required=True, + help="Output directory (/include/generated)") + parser.add_argument("--datapct", required=True, + help="Multipler to the size of reserved space for DATA region") + parser.add_argument("--rodata", required=True, + help="Extra bytes to reserve for RODATA region") + parser.add_argument("-v", "--verbose", action="store_true", + help="Verbose messages") + args = parser.parse_args() + if "VERBOSE" in os.environ: + args.verbose = 1 + + +def main(): + """Main program""" + parse_args() + + with open(args.object, "rb") as obj_fp: + obj = ELFFile(obj_fp) + + generate_linker_headers(obj) + + +if __name__ == "__main__": + main()