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 <daniel.leung@intel.com>
This commit is contained in:
parent
317dcd908f
commit
1117169980
132
CMakeLists.txt
132
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 $<TARGET_FILE:app_smem_unaligned_prebuilt>
|
||||
--gperf-output ${KOBJECT_PREBUILT_HASH_LIST}
|
||||
${gen_kobject_list_include_args}
|
||||
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--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"
|
||||
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--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}
|
||||
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
24
arch/Kconfig
24
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
|
||||
|
|
|
@ -188,7 +188,7 @@ SECTIONS {
|
|||
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
||||
|
||||
#include <linker/common-ram.ld>
|
||||
#include <linker/kobject.ld>
|
||||
#include <linker/kobject-data.ld>
|
||||
|
||||
#ifdef __MWDT_LINKER_CMD__
|
||||
/* TODO: add mwdt specific RAM C++ sections */
|
||||
|
|
|
@ -295,7 +295,7 @@ SECTIONS
|
|||
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
||||
|
||||
#include <linker/common-ram.ld>
|
||||
#include <linker/kobject.ld>
|
||||
#include <linker/kobject-data.ld>
|
||||
#include <linker/cplusplus-ram.ld>
|
||||
|
||||
__data_ram_end = .;
|
||||
|
|
|
@ -329,7 +329,7 @@ SECTIONS
|
|||
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
||||
|
||||
#include <linker/common-ram.ld>
|
||||
#include <linker/kobject.ld>
|
||||
#include <linker/kobject-data.ld>
|
||||
|
||||
#include <linker/cplusplus-ram.ld>
|
||||
|
||||
|
|
|
@ -271,7 +271,7 @@ SECTIONS
|
|||
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
||||
|
||||
#include <linker/common-ram.ld>
|
||||
#include <linker/kobject.ld>
|
||||
#include <linker/kobject-data.ld>
|
||||
#include <linker/cplusplus-ram.ld>
|
||||
|
||||
__data_ram_end = .;
|
||||
|
|
|
@ -225,7 +225,7 @@ SECTIONS
|
|||
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
||||
|
||||
#include <linker/common-ram.ld>
|
||||
#include <linker/kobject.ld>
|
||||
#include <linker/kobject-data.ld>
|
||||
|
||||
/* Located in generated directory. This file is populated by the
|
||||
* zephyr_linker_sources() Cmake function.
|
||||
|
|
|
@ -336,7 +336,7 @@ SECTIONS
|
|||
#include <arch/x86/pagetables.ld>
|
||||
|
||||
/* Must be last in RAM */
|
||||
#include <linker/kobject.ld>
|
||||
#include <linker/kobject-data.ld>
|
||||
|
||||
MMU_PAGE_ALIGN
|
||||
__data_ram_end = .;
|
||||
|
|
|
@ -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 <arch/x86/pagetables.ld>
|
||||
|
||||
/* Must be last in RAM */
|
||||
#include <linker/kobject.ld>
|
||||
#include <linker/kobject-data.ld>
|
||||
MMU_PAGE_ALIGN
|
||||
_image_ram_end = .;
|
||||
z_mapped_end = .;
|
||||
|
|
|
@ -24,3 +24,5 @@ SECTION_PROLOGUE(_NOINIT_SECTION_NAME,(NOLOAD),)
|
|||
#include <snippets-noinit.ld>
|
||||
|
||||
} GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||
|
||||
#include "kobject-priv-stacks.ld"
|
||||
|
|
75
include/linker/kobject-data.ld
Normal file
75
include/linker/kobject-data.ld
Normal file
|
@ -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 <linker-kobject-prebuilt-data.h>
|
||||
|
||||
#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 <linker-kobject-prebuilt-data.h>
|
||||
#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 */
|
58
include/linker/kobject-priv-stacks.ld
Normal file
58
include/linker/kobject-priv-stacks.ld
Normal file
|
@ -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 <linker-kobject-prebuilt-priv-stacks.h>
|
||||
#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 <linker-kobject-prebuilt-priv-stacks.h>
|
||||
#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 */
|
|
@ -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 <linker-kobject-prebuilt-rodata.h>
|
||||
#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 <linker-kobject-prebuilt-rodata.h>
|
||||
#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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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; \
|
||||
|
|
|
@ -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();
|
||||
|
|
24
kernel/mmu.c
24
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;
|
||||
|
|
139
scripts/gen_kobject_placeholders.py
Executable file
139
scripts/gen_kobject_placeholders.py
Executable file
|
@ -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 (<build_dir>/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()
|
Loading…
Reference in a new issue