kernel: delete separate logic for priv stacks
This never needed to be put in a separate gperf table. Privilege mode stacks can be generated by the main gen_kobject_list.py logic, which we do here. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
ae8acffaa6
commit
28be793cb6
21 changed files with 124 additions and 474 deletions
186
CMakeLists.txt
186
CMakeLists.txt
|
@ -351,9 +351,6 @@ endif()
|
||||||
if(CONFIG_USERSPACE)
|
if(CONFIG_USERSPACE)
|
||||||
set(APP_SMEM_ALIGNED_DEP app_smem_aligned_linker)
|
set(APP_SMEM_ALIGNED_DEP app_smem_aligned_linker)
|
||||||
set(APP_SMEM_UNALIGNED_DEP app_smem_unaligned_linker)
|
set(APP_SMEM_UNALIGNED_DEP app_smem_unaligned_linker)
|
||||||
if(CONFIG_ARM)
|
|
||||||
set(PRIV_STACK_DEP priv_stacks_prebuilt)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
get_property(TOPT GLOBAL PROPERTY TOPT)
|
get_property(TOPT GLOBAL PROPERTY TOPT)
|
||||||
|
@ -706,7 +703,6 @@ endif() # CONFIG_CODE_DATA_RELOCATION
|
||||||
configure_linker_script(
|
configure_linker_script(
|
||||||
linker.cmd
|
linker.cmd
|
||||||
""
|
""
|
||||||
${PRIV_STACK_DEP}
|
|
||||||
${APP_SMEM_ALIGNED_DEP}
|
${APP_SMEM_ALIGNED_DEP}
|
||||||
${CODE_RELOCATION_DEP}
|
${CODE_RELOCATION_DEP}
|
||||||
zephyr_generated_headers
|
zephyr_generated_headers
|
||||||
|
@ -786,147 +782,7 @@ if(CONFIG_USERSPACE)
|
||||||
|
|
||||||
get_property(compile_definitions_interface TARGET zephyr_interface
|
get_property(compile_definitions_interface TARGET zephyr_interface
|
||||||
PROPERTY INTERFACE_COMPILE_DEFINITIONS)
|
PROPERTY INTERFACE_COMPILE_DEFINITIONS)
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# Warning most of this gperf code is duplicated below for
|
|
||||||
# gen_kobject_list.py / output_lib
|
|
||||||
if(CONFIG_ARM AND CONFIG_USERSPACE)
|
|
||||||
set(GEN_PRIV_STACKS $ENV{ZEPHYR_BASE}/scripts/gen_priv_stacks.py)
|
|
||||||
set(PROCESS_PRIV_STACKS_GPERF $ENV{ZEPHYR_BASE}/scripts/process_gperf.py)
|
|
||||||
|
|
||||||
set(PRIV_STACKS priv_stacks_hash.gperf)
|
|
||||||
set(PRIV_STACKS_OUTPUT_SRC_PRE priv_stacks_hash_preprocessed.c)
|
|
||||||
set(PRIV_STACKS_OUTPUT_SRC priv_stacks_hash.c)
|
|
||||||
set(PRIV_STACKS_OUTPUT_OBJ priv_stacks_hash.c.obj)
|
|
||||||
set(PRIV_STACKS_OUTPUT_OBJ_RENAMED priv_stacks_hash_renamed.o)
|
|
||||||
|
|
||||||
# Essentially what we are doing here is extracting some information
|
|
||||||
# out of the nearly finished elf file, generating the source code
|
|
||||||
# for a hash table based on that information, and then compiling and
|
|
||||||
# linking the hash table back into a now even more nearly finished
|
|
||||||
# elf file.
|
|
||||||
|
|
||||||
# Use the script GEN_PRIV_STACKS to scan the kernel binary's
|
|
||||||
# (${ZEPHYR_PREBUILT_EXECUTABLE}) DWARF information to produce a table of kernel
|
|
||||||
# objects (PRIV_STACKS) which we will then pass to gperf
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${PRIV_STACKS}
|
|
||||||
COMMAND
|
|
||||||
${PYTHON_EXECUTABLE}
|
|
||||||
${GEN_PRIV_STACKS}
|
|
||||||
--kernel $<TARGET_FILE:priv_stacks_prebuilt>
|
|
||||||
--output ${PRIV_STACKS}
|
|
||||||
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
|
|
||||||
DEPENDS priv_stacks_prebuilt
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
add_custom_target(priv_stacks DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS})
|
|
||||||
|
|
||||||
if(${GPERF} STREQUAL GPERF-NOTFOUND)
|
|
||||||
message(FATAL_ERROR "Unable to find gperf")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Use gperf to generate C code (PRIV_STACKS_OUTPUT_SRC_PRE) which implements a
|
|
||||||
# perfect hashtable based on PRIV_STACKS
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${PRIV_STACKS_OUTPUT_SRC_PRE}
|
|
||||||
COMMAND
|
|
||||||
${GPERF} -C
|
|
||||||
--output-file ${PRIV_STACKS_OUTPUT_SRC_PRE}
|
|
||||||
${PRIV_STACKS}
|
|
||||||
DEPENDS priv_stacks ${PRIV_STACKS}
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
add_custom_target(priv_stacks_output_src_pre DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC_PRE})
|
|
||||||
|
|
||||||
# For our purposes the code/data generated by gperf is not optimal.
|
|
||||||
#
|
|
||||||
# The script PROCESS_GPERF creates a new c file OUTPUT_SRC based on
|
|
||||||
# OUTPUT_SRC_PRE to greatly reduce the amount of code/data generated
|
|
||||||
# since we know we are always working with pointer values
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${PRIV_STACKS_OUTPUT_SRC}
|
|
||||||
COMMAND
|
|
||||||
${PYTHON_EXECUTABLE}
|
|
||||||
${PROCESS_PRIV_STACKS_GPERF}
|
|
||||||
-i ${PRIV_STACKS_OUTPUT_SRC_PRE}
|
|
||||||
-o ${PRIV_STACKS_OUTPUT_SRC}
|
|
||||||
-p "struct _k_priv_stack_map"
|
|
||||||
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
|
|
||||||
DEPENDS priv_stacks_output_src_pre ${PRIV_STACKS_OUTPUT_SRC_PRE}
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
add_custom_target(priv_stacks_output_src DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC})
|
|
||||||
|
|
||||||
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC}
|
|
||||||
PROPERTIES COMPILE_DEFINITIONS "${compile_definitions_interface}")
|
|
||||||
|
|
||||||
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC}
|
|
||||||
PROPERTIES COMPILE_FLAGS
|
|
||||||
"${NO_COVERAGE_FLAGS} -fno-function-sections -fno-data-sections ")
|
|
||||||
|
|
||||||
# We need precise control of where generated text/data ends up in the final
|
|
||||||
# kernel image. Disable function/data sections and use objcopy to move
|
|
||||||
# generated data into special section names
|
|
||||||
add_library(priv_stacks_output_lib STATIC
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Turn off -ffunction-sections, etc.
|
|
||||||
# NB: Using a library instead of target_compile_options(priv_stacks_output_lib
|
|
||||||
# [...]) because a library's options have precedence
|
|
||||||
add_library(priv_stacks_output_lib_interface INTERFACE)
|
|
||||||
foreach(incl ${include_dir_in_interface})
|
|
||||||
target_include_directories(priv_stacks_output_lib_interface INTERFACE ${incl})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
foreach(incl ${sys_include_dir_in_interface})
|
|
||||||
target_include_directories(priv_stacks_output_lib_interface SYSTEM INTERFACE ${incl})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
target_link_libraries(priv_stacks_output_lib priv_stacks_output_lib_interface)
|
|
||||||
|
|
||||||
set(PRIV_STACKS_OUTPUT_OBJ_PATH ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/priv_stacks_output_lib.dir/${PRIV_STACKS_OUTPUT_OBJ})
|
|
||||||
|
|
||||||
set(obj_copy_cmd "")
|
|
||||||
set(obj_copy_sections_rename
|
|
||||||
.bss=.priv_stacks.noinit
|
|
||||||
.data=.priv_stacks.data
|
|
||||||
.text=.priv_stacks.text
|
|
||||||
.rodata=.priv_stacks.rodata
|
|
||||||
)
|
|
||||||
bintools_objcopy(
|
|
||||||
RESULT_CMD_LIST obj_copy_cmd
|
|
||||||
SECTION_RENAME ${obj_copy_sections_rename}
|
|
||||||
FILE_INPUT ${PRIV_STACKS_OUTPUT_OBJ_PATH}
|
|
||||||
FILE_OUTPUT ${PRIV_STACKS_OUTPUT_OBJ_RENAMED}
|
|
||||||
)
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_OBJ_RENAMED}
|
|
||||||
${obj_copy_cmd}
|
|
||||||
DEPENDS priv_stacks_output_lib
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
add_custom_target(priv_stacks_output_obj_renamed DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_OBJ_RENAMED})
|
|
||||||
|
|
||||||
add_library(priv_stacks_output_obj_renamed_lib STATIC IMPORTED GLOBAL)
|
|
||||||
set_property(
|
|
||||||
TARGET priv_stacks_output_obj_renamed_lib
|
|
||||||
PROPERTY
|
|
||||||
IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_OBJ_RENAMED}
|
|
||||||
)
|
|
||||||
add_dependencies(
|
|
||||||
priv_stacks_output_obj_renamed_lib
|
|
||||||
priv_stacks_output_obj_renamed
|
|
||||||
)
|
|
||||||
|
|
||||||
set_property(GLOBAL APPEND PROPERTY GENERATED_KERNEL_OBJECT_FILES priv_stacks_output_obj_renamed_lib)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Warning: most of this gperf code is duplicated above for
|
|
||||||
# gen_priv_stacks.py / priv_stacks_output_lib
|
|
||||||
if(CONFIG_USERSPACE)
|
|
||||||
set(GEN_KOBJ_LIST ${ZEPHYR_BASE}/scripts/gen_kobject_list.py)
|
set(GEN_KOBJ_LIST ${ZEPHYR_BASE}/scripts/gen_kobject_list.py)
|
||||||
set(PROCESS_GPERF ${ZEPHYR_BASE}/scripts/process_gperf.py)
|
set(PROCESS_GPERF ${ZEPHYR_BASE}/scripts/process_gperf.py)
|
||||||
|
|
||||||
|
@ -1168,42 +1024,6 @@ if(CONFIG_USERSPACE)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CONFIG_USERSPACE AND CONFIG_ARM)
|
|
||||||
configure_linker_script(
|
|
||||||
linker_priv_stacks.cmd
|
|
||||||
""
|
|
||||||
${CODE_RELOCATION_DEP}
|
|
||||||
${APP_SMEM_ALIGNED_DEP}
|
|
||||||
${APP_SMEM_ALIGNED_LD}
|
|
||||||
zephyr_generated_headers
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_target(
|
|
||||||
linker_priv_stacks_script
|
|
||||||
DEPENDS
|
|
||||||
linker_priv_stacks.cmd
|
|
||||||
)
|
|
||||||
|
|
||||||
set_property(TARGET
|
|
||||||
linker_priv_stacks_script
|
|
||||||
PROPERTY INCLUDE_DIRECTORIES
|
|
||||||
${ZEPHYR_INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
set(PRIV_STACK_LIB priv_stacks_output_obj_renamed_lib)
|
|
||||||
add_executable( priv_stacks_prebuilt misc/empty_file.c)
|
|
||||||
toolchain_ld_link_elf(
|
|
||||||
TARGET_ELF priv_stacks_prebuilt
|
|
||||||
OUTPUT_MAP ${PROJECT_BINARY_DIR}/priv_stacks_prebuilt.map
|
|
||||||
LIBRARIES_PRE_SCRIPT ""
|
|
||||||
LINKER_SCRIPT ${PROJECT_BINARY_DIR}/linker_priv_stacks.cmd
|
|
||||||
LIBRARIES_POST_SCRIPT ""
|
|
||||||
DEPENDENCIES ${CODE_RELOCATION_DEP}
|
|
||||||
)
|
|
||||||
set_property(TARGET priv_stacks_prebuilt PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker_priv_stacks.cmd)
|
|
||||||
add_dependencies( priv_stacks_prebuilt linker_priv_stacks_script ${OFFSETS_LIB})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# FIXME: Is there any way to get rid of empty_file.c?
|
# FIXME: Is there any way to get rid of empty_file.c?
|
||||||
add_executable( ${ZEPHYR_PREBUILT_EXECUTABLE} misc/empty_file.c)
|
add_executable( ${ZEPHYR_PREBUILT_EXECUTABLE} misc/empty_file.c)
|
||||||
toolchain_ld_link_elf(
|
toolchain_ld_link_elf(
|
||||||
|
@ -1211,11 +1031,10 @@ toolchain_ld_link_elf(
|
||||||
OUTPUT_MAP ${PROJECT_BINARY_DIR}/${ZEPHYR_PREBUILT_EXECUTABLE}.map
|
OUTPUT_MAP ${PROJECT_BINARY_DIR}/${ZEPHYR_PREBUILT_EXECUTABLE}.map
|
||||||
LIBRARIES_PRE_SCRIPT ""
|
LIBRARIES_PRE_SCRIPT ""
|
||||||
LINKER_SCRIPT ${PROJECT_BINARY_DIR}/linker.cmd
|
LINKER_SCRIPT ${PROJECT_BINARY_DIR}/linker.cmd
|
||||||
LIBRARIES_POST_SCRIPT ${PRIV_STACK_LIB}
|
|
||||||
DEPENDENCIES ${CODE_RELOCATION_DEP}
|
DEPENDENCIES ${CODE_RELOCATION_DEP}
|
||||||
)
|
)
|
||||||
set_property(TARGET ${ZEPHYR_PREBUILT_EXECUTABLE} PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker.cmd)
|
set_property(TARGET ${ZEPHYR_PREBUILT_EXECUTABLE} PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker.cmd)
|
||||||
add_dependencies( ${ZEPHYR_PREBUILT_EXECUTABLE} ${PRIV_STACK_DEP} ${LINKER_SCRIPT_TARGET} ${OFFSETS_LIB})
|
add_dependencies( ${ZEPHYR_PREBUILT_EXECUTABLE} ${LINKER_SCRIPT_TARGET} ${OFFSETS_LIB})
|
||||||
|
|
||||||
|
|
||||||
set(generated_kernel_files ${GKSF} ${GKOF})
|
set(generated_kernel_files ${GKSF} ${GKOF})
|
||||||
|
@ -1230,7 +1049,6 @@ else()
|
||||||
configure_linker_script(
|
configure_linker_script(
|
||||||
linker_pass_final.cmd
|
linker_pass_final.cmd
|
||||||
"-DLINKER_PASS2"
|
"-DLINKER_PASS2"
|
||||||
${PRIV_STACK_DEP}
|
|
||||||
${CODE_RELOCATION_DEP}
|
${CODE_RELOCATION_DEP}
|
||||||
${ZEPHYR_PREBUILT_EXECUTABLE}
|
${ZEPHYR_PREBUILT_EXECUTABLE}
|
||||||
zephyr_generated_headers
|
zephyr_generated_headers
|
||||||
|
@ -1258,7 +1076,7 @@ else()
|
||||||
DEPENDENCIES ${CODE_RELOCATION_DEP}
|
DEPENDENCIES ${CODE_RELOCATION_DEP}
|
||||||
)
|
)
|
||||||
set_property(TARGET ${ZEPHYR_FINAL_EXECUTABLE} PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker_pass_final.cmd)
|
set_property(TARGET ${ZEPHYR_FINAL_EXECUTABLE} PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker_pass_final.cmd)
|
||||||
add_dependencies( ${ZEPHYR_FINAL_EXECUTABLE} ${PRIV_STACK_DEP} ${LINKER_PASS_FINAL_SCRIPT_TARGET})
|
add_dependencies( ${ZEPHYR_FINAL_EXECUTABLE} ${LINKER_PASS_FINAL_SCRIPT_TARGET})
|
||||||
|
|
||||||
# Use the pass2 elf as the final elf
|
# Use the pass2 elf as the final elf
|
||||||
set(logical_target_for_zephyr_elf ${ZEPHYR_FINAL_EXECUTABLE})
|
set(logical_target_for_zephyr_elf ${ZEPHYR_FINAL_EXECUTABLE})
|
||||||
|
|
|
@ -383,7 +383,6 @@
|
||||||
/arch/x86/gen_gdt.py @andrewboie
|
/arch/x86/gen_gdt.py @andrewboie
|
||||||
/arch/x86/gen_idt.py @andrewboie
|
/arch/x86/gen_idt.py @andrewboie
|
||||||
/scripts/gen_kobject_list.py @andrewboie
|
/scripts/gen_kobject_list.py @andrewboie
|
||||||
/scripts/gen_priv_stacks.py @andrewboie @agross-oss @ioannisg
|
|
||||||
/scripts/gen_syscalls.py @andrewboie
|
/scripts/gen_syscalls.py @andrewboie
|
||||||
/scripts/net/ @jukkar @pfl
|
/scripts/net/ @jukkar @pfl
|
||||||
/scripts/process_gperf.py @andrewboie
|
/scripts/process_gperf.py @andrewboie
|
||||||
|
|
25
arch/Kconfig
25
arch/Kconfig
|
@ -27,6 +27,9 @@ config ARM
|
||||||
bool
|
bool
|
||||||
select ARCH_IS_SET
|
select ARCH_IS_SET
|
||||||
select HAS_DTS
|
select HAS_DTS
|
||||||
|
# FIXME: current state of the code for all ARM requires this, but
|
||||||
|
# is really only necessary for Cortex-M with ARM MPU!
|
||||||
|
select GEN_PRIV_STACKS
|
||||||
help
|
help
|
||||||
ARM architecture
|
ARM architecture
|
||||||
|
|
||||||
|
@ -218,15 +221,8 @@ config PRIVILEGED_STACK_SIZE
|
||||||
This option sets the privileged stack region size that will be used
|
This option sets the privileged stack region size that will be used
|
||||||
in addition to the user mode thread stack. During normal execution,
|
in addition to the user mode thread stack. During normal execution,
|
||||||
this region will be inaccessible from user mode. During system calls,
|
this region will be inaccessible from user mode. During system calls,
|
||||||
this region will be utilized by the system call.
|
this region will be utilized by the system call. This value must be
|
||||||
|
a multiple of the minimum stack alignment.
|
||||||
config PRIVILEGED_STACK_TEXT_AREA
|
|
||||||
int "Privileged stacks text area"
|
|
||||||
default 512 if COVERAGE_GCOV
|
|
||||||
default 256
|
|
||||||
depends on ARCH_HAS_USERSPACE
|
|
||||||
help
|
|
||||||
Stack text area size for privileged stacks.
|
|
||||||
|
|
||||||
config KOBJECT_TEXT_AREA
|
config KOBJECT_TEXT_AREA
|
||||||
int "Size if kobject text area"
|
int "Size if kobject text area"
|
||||||
|
@ -237,6 +233,17 @@ config KOBJECT_TEXT_AREA
|
||||||
help
|
help
|
||||||
Size of kernel object text area. Used in linker script.
|
Size of kernel object text area. Used in linker script.
|
||||||
|
|
||||||
|
config GEN_PRIV_STACKS
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Selected if the architecture requires that privilege elevation stacks
|
||||||
|
be allocated in a separate memory area. This is typical of arches
|
||||||
|
whose MPUs require regions to be power-of-two aligned/sized.
|
||||||
|
|
||||||
|
FIXME: This should be removed and replaced with checks against
|
||||||
|
CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT, but both ARM and ARC
|
||||||
|
changes will be necessary for this.
|
||||||
|
|
||||||
config STACK_GROWS_UP
|
config STACK_GROWS_UP
|
||||||
bool "Stack grows towards higher memory addresses"
|
bool "Stack grows towards higher memory addresses"
|
||||||
help
|
help
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
#include <ksched.h>
|
#include <ksched.h>
|
||||||
#include <wait_q.h>
|
#include <wait_q.h>
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
|
||||||
extern u8_t *z_priv_stack_find(void *obj);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* An initial context, to be "restored" by z_arm_pendsv(), is put at the other
|
/* An initial context, to be "restored" by z_arm_pendsv(), is put at the other
|
||||||
* end of the stack, and thus reusable by the stack when not needed anymore.
|
* end of the stack, and thus reusable by the stack when not needed anymore.
|
||||||
*
|
*
|
||||||
|
|
|
@ -230,15 +230,6 @@ The following is a detailed description of the scripts used during the build pro
|
||||||
:start-after: """
|
:start-after: """
|
||||||
:end-before: """
|
:end-before: """
|
||||||
|
|
||||||
.. _gen_priv_stacks.py:
|
|
||||||
|
|
||||||
:zephyr_file:`scripts/gen_priv_stacks.py`
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
.. include:: ../../../scripts/gen_priv_stacks.py
|
|
||||||
:start-after: """
|
|
||||||
:end-before: """
|
|
||||||
|
|
||||||
.. _gen_idt.py:
|
.. _gen_idt.py:
|
||||||
|
|
||||||
:zephyr_file:`arch/x86/gen_idt.py`
|
:zephyr_file:`arch/x86/gen_idt.py`
|
||||||
|
|
|
@ -8,7 +8,7 @@ set of stacks. These stacks exist in a 1:1 relationship with each thread stack
|
||||||
defined in the system. The privileged stacks are created as a part of the
|
defined in the system. The privileged stacks are created as a part of the
|
||||||
build process.
|
build process.
|
||||||
|
|
||||||
A post-build script :ref:`gen_priv_stacks.py` scans the generated
|
A post-build script :ref:`gen_kobject_list.py` scans the generated
|
||||||
ELF file and finds all of the thread stack objects. A set of privileged
|
ELF file and finds all of the thread stack objects. A set of privileged
|
||||||
stacks, a lookup table, and a set of helper functions are created and added
|
stacks, a lookup table, and a set of helper functions are created and added
|
||||||
to the image.
|
to the image.
|
||||||
|
|
|
@ -156,7 +156,6 @@ SECTIONS
|
||||||
{
|
{
|
||||||
_image_text_start = .;
|
_image_text_start = .;
|
||||||
|
|
||||||
#include <linker/priv_stacks-text.ld>
|
|
||||||
#include <linker/kobject-text.ld>
|
#include <linker/kobject-text.ld>
|
||||||
|
|
||||||
*(.text)
|
*(.text)
|
||||||
|
@ -221,7 +220,6 @@ SECTIONS
|
||||||
#include <custom-rodata.ld>
|
#include <custom-rodata.ld>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linker/priv_stacks-rom.ld>
|
|
||||||
#include <linker/kobject-rom.ld>
|
#include <linker/kobject-rom.ld>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -373,10 +371,8 @@ SECTIONS
|
||||||
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
||||||
|
|
||||||
#include <linker/common-ram.ld>
|
#include <linker/common-ram.ld>
|
||||||
#include <linker/priv_stacks.ld>
|
|
||||||
#include <linker/kobject.ld>
|
#include <linker/kobject.ld>
|
||||||
|
|
||||||
#include <linker/priv_stacks-noinit.ld>
|
|
||||||
#include <linker/cplusplus-ram.ld>
|
#include <linker/cplusplus-ram.ld>
|
||||||
|
|
||||||
__data_ram_end = .;
|
__data_ram_end = .;
|
||||||
|
|
|
@ -143,7 +143,6 @@ SECTIONS
|
||||||
*/
|
*/
|
||||||
*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
|
*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
|
||||||
|
|
||||||
#include <linker/priv_stacks-text.ld>
|
|
||||||
#include <linker/kobject-text.ld>
|
#include <linker/kobject-text.ld>
|
||||||
|
|
||||||
} GROUP_LINK_IN(ROMABLE_REGION)
|
} GROUP_LINK_IN(ROMABLE_REGION)
|
||||||
|
@ -198,7 +197,6 @@ SECTIONS
|
||||||
#include <custom-rodata.ld>
|
#include <custom-rodata.ld>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linker/priv_stacks-rom.ld>
|
|
||||||
#include <linker/kobject-rom.ld>
|
#include <linker/kobject-rom.ld>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -333,11 +331,7 @@ SECTIONS
|
||||||
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
||||||
|
|
||||||
#include <linker/common-ram.ld>
|
#include <linker/common-ram.ld>
|
||||||
#include <linker/priv_stacks.ld>
|
|
||||||
#include <linker/kobject.ld>
|
#include <linker/kobject.ld>
|
||||||
|
|
||||||
#include <linker/priv_stacks-noinit.ld>
|
|
||||||
|
|
||||||
#include <linker/cplusplus-ram.ld>
|
#include <linker/cplusplus-ram.ld>
|
||||||
|
|
||||||
__data_ram_end = .;
|
__data_ram_end = .;
|
||||||
|
|
|
@ -132,7 +132,6 @@ SECTIONS
|
||||||
*/
|
*/
|
||||||
*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
|
*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
|
||||||
|
|
||||||
#include <linker/priv_stacks-text.ld>
|
|
||||||
#include <linker/kobject-text.ld>
|
#include <linker/kobject-text.ld>
|
||||||
|
|
||||||
MMU_ALIGN;
|
MMU_ALIGN;
|
||||||
|
@ -194,7 +193,6 @@ SECTIONS
|
||||||
#include <custom-rodata.ld>
|
#include <custom-rodata.ld>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linker/priv_stacks-rom.ld>
|
|
||||||
#include <linker/kobject-rom.ld>
|
#include <linker/kobject-rom.ld>
|
||||||
|
|
||||||
} GROUP_LINK_IN(ROMABLE_REGION)
|
} GROUP_LINK_IN(ROMABLE_REGION)
|
||||||
|
@ -319,11 +317,7 @@ SECTIONS
|
||||||
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
|
||||||
|
|
||||||
#include <linker/common-ram.ld>
|
#include <linker/common-ram.ld>
|
||||||
#include <linker/priv_stacks.ld>
|
|
||||||
#include <linker/kobject.ld>
|
#include <linker/kobject.ld>
|
||||||
|
|
||||||
#include <linker/priv_stacks-noinit.ld>
|
|
||||||
|
|
||||||
#include <linker/cplusplus-ram.ld>
|
#include <linker/cplusplus-ram.ld>
|
||||||
|
|
||||||
__data_ram_end = .;
|
__data_ram_end = .;
|
||||||
|
|
|
@ -166,6 +166,17 @@ enum k_objects {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
#ifdef CONFIG_USERSPACE
|
||||||
|
#ifdef CONFIG_GEN_PRIV_STACKS
|
||||||
|
/* Metadata struct for K_OBJ_THREAD_STACK_ELEMENT */
|
||||||
|
struct z_stack_data {
|
||||||
|
/* Size of the entire stack object, including reserved areas */
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/* Stack buffer for privilege mode elevations */
|
||||||
|
u8_t *priv;
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_GEN_PRIV_STACKS */
|
||||||
|
|
||||||
/* Object extra data. Only some objects use this, determined by object type */
|
/* Object extra data. Only some objects use this, determined by object type */
|
||||||
union z_object_data {
|
union z_object_data {
|
||||||
/* Backing mutex for K_OBJ_SYS_MUTEX */
|
/* Backing mutex for K_OBJ_SYS_MUTEX */
|
||||||
|
@ -174,8 +185,13 @@ union z_object_data {
|
||||||
/* Numerical thread ID for K_OBJ_THREAD */
|
/* Numerical thread ID for K_OBJ_THREAD */
|
||||||
unsigned int thread_id;
|
unsigned int thread_id;
|
||||||
|
|
||||||
|
#ifdef CONFIG_GEN_PRIV_STACKS
|
||||||
|
/* Metadata for K_OBJ_THREAD_STACK_ELEMENT */
|
||||||
|
struct z_stack_data *stack_data;
|
||||||
|
#else
|
||||||
/* Stack buffer size for K_OBJ_THREAD_STACK_ELEMENT */
|
/* Stack buffer size for K_OBJ_THREAD_STACK_ELEMENT */
|
||||||
size_t stack_size;
|
size_t stack_size;
|
||||||
|
#endif /* CONFIG_GEN_PRIV_STACKS */
|
||||||
|
|
||||||
/* Futex wait queue and spinlock for K_OBJ_FUTEX */
|
/* Futex wait queue and spinlock for K_OBJ_FUTEX */
|
||||||
struct z_futex_data *futex_data;
|
struct z_futex_data *futex_data;
|
||||||
|
|
|
@ -39,5 +39,13 @@
|
||||||
*(".kobject_data.rodata*")
|
*(".kobject_data.rodata*")
|
||||||
#endif
|
#endif
|
||||||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||||
#endif /* CONFIG_USERSPACE */
|
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Linaro Limited.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
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)
|
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Linaro Limited.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
|
||||||
/* Kept in RAM on non-XIP */
|
|
||||||
#ifdef CONFIG_XIP
|
|
||||||
*(".priv_stacks.rodata*")
|
|
||||||
#endif
|
|
||||||
#endif /* CONFIG_USERSPACE */
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Linaro Limited.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_USERSPACE
|
|
||||||
/* We need to reserve room for the gperf generated hash functions.
|
|
||||||
* Fortunately, unlike the data tables, the size of the code is
|
|
||||||
* reasonably predictable.
|
|
||||||
*/
|
|
||||||
_priv_stacks_text_area_start = .;
|
|
||||||
*(".priv_stacks.text*")
|
|
||||||
_priv_stacks_text_area_end = .;
|
|
||||||
|
|
||||||
_priv_stacks_text_area_used = _priv_stacks_text_area_end - _priv_stacks_text_area_start;
|
|
||||||
|
|
||||||
#ifndef LINKER_PASS2
|
|
||||||
PROVIDE(z_priv_stack_find = .);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* In a valid build the MAX function will always evaluate to the
|
|
||||||
second argument below, but to give the user a good error message
|
|
||||||
when the area overflows we need to temporarily corrupt the
|
|
||||||
location counter, and then detect the overflow with an assertion
|
|
||||||
later on. */
|
|
||||||
|
|
||||||
. = MAX(., _priv_stacks_text_area_start + CONFIG_PRIVILEGED_STACK_TEXT_AREA);
|
|
||||||
|
|
||||||
ASSERT(
|
|
||||||
CONFIG_PRIVILEGED_STACK_TEXT_AREA >= _priv_stacks_text_area_used,
|
|
||||||
"The configuration system has incorrectly set
|
|
||||||
'CONFIG_PRIVILEGED_STACK_TEXT_AREA' to
|
|
||||||
CONFIG_PRIVILEGED_STACK_TEXT_AREA, which is not big enough. You must
|
|
||||||
through Kconfig either disable 'CONFIG_USERSPACE', or set
|
|
||||||
'CONFIG_PRIVILEGED_STACK_TEXT_AREA' to a value larger than
|
|
||||||
CONFIG_PRIVILEGED_STACK_TEXT_AREA."
|
|
||||||
);
|
|
||||||
#endif /* CONFIG_USERSPACE */
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Linaro Limited
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
|
||||||
/* Constraints:
|
|
||||||
*
|
|
||||||
* - changes to the size of this section between build phases
|
|
||||||
* *must not* shift the memory address of any kernel objects,
|
|
||||||
* 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 compiling it.
|
|
||||||
*/
|
|
||||||
SECTION_DATA_PROLOGUE(priv_stacks,,)
|
|
||||||
{
|
|
||||||
*(".priv_stacks.data*")
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
*(".priv_stacks.rodata*")
|
|
||||||
#endif
|
|
||||||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
|
||||||
#endif /* CONFIG_USERSPACE */
|
|
||||||
|
|
|
@ -124,6 +124,10 @@ extern struct k_thread z_idle_threads[CONFIG_MP_NUM_CPUS];
|
||||||
extern K_THREAD_STACK_ARRAY_DEFINE(z_interrupt_stacks, CONFIG_MP_NUM_CPUS,
|
extern K_THREAD_STACK_ARRAY_DEFINE(z_interrupt_stacks, CONFIG_MP_NUM_CPUS,
|
||||||
CONFIG_ISR_STACK_SIZE);
|
CONFIG_ISR_STACK_SIZE);
|
||||||
|
|
||||||
|
#ifdef CONFIG_GEN_PRIV_STACKS
|
||||||
|
extern u8_t *z_priv_stack_find(k_thread_stack_t *stack);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -641,7 +641,7 @@ k_tid_t z_vrfy_k_thread_create(struct k_thread *new_thread,
|
||||||
void *p1, void *p2, void *p3,
|
void *p1, void *p2, void *p3,
|
||||||
int prio, u32_t options, s32_t delay)
|
int prio, u32_t options, s32_t delay)
|
||||||
{
|
{
|
||||||
size_t total_size;
|
size_t total_size, stack_obj_size;
|
||||||
struct z_object *stack_object;
|
struct z_object *stack_object;
|
||||||
|
|
||||||
/* The thread and stack objects *must* be in an uninitialized state */
|
/* The thread and stack objects *must* be in an uninitialized state */
|
||||||
|
@ -664,9 +664,14 @@ k_tid_t z_vrfy_k_thread_create(struct k_thread *new_thread,
|
||||||
/* Testing less-than-or-equal since additional room may have been
|
/* Testing less-than-or-equal since additional room may have been
|
||||||
* allocated for alignment constraints
|
* allocated for alignment constraints
|
||||||
*/
|
*/
|
||||||
Z_OOPS(Z_SYSCALL_VERIFY_MSG(total_size <= stack_object->data.stack_size,
|
#ifdef CONFIG_GEN_PRIV_STACKS
|
||||||
|
stack_obj_size = stack_object->data.stack_data->size;
|
||||||
|
#else
|
||||||
|
stack_obj_size = stack_object->data.stack_size;
|
||||||
|
#endif
|
||||||
|
Z_OOPS(Z_SYSCALL_VERIFY_MSG(total_size <= stack_obj_size,
|
||||||
"stack size %zu is too big, max is %zu",
|
"stack size %zu is too big, max is %zu",
|
||||||
total_size, stack_object->data.stack_size));
|
total_size, stack_obj_size));
|
||||||
|
|
||||||
/* User threads may only create other user threads and they can't
|
/* User threads may only create other user threads and they can't
|
||||||
* be marked as essential
|
* be marked as essential
|
||||||
|
|
|
@ -90,6 +90,25 @@ struct perm_ctx {
|
||||||
struct k_thread *parent;
|
struct k_thread *parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_GEN_PRIV_STACKS
|
||||||
|
/* See write_gperf_table() in scripts/gen_kobject_list.py. The privilege
|
||||||
|
* mode stacks are allocated as an array. The base of the array is
|
||||||
|
* aligned to Z_PRIVILEGE_STACK_ALIGN, and all members must be as well.
|
||||||
|
*/
|
||||||
|
BUILD_ASSERT(CONFIG_PRIVILEGED_STACK_SIZE % Z_PRIVILEGE_STACK_ALIGN == 0);
|
||||||
|
|
||||||
|
u8_t *z_priv_stack_find(k_thread_stack_t *stack)
|
||||||
|
{
|
||||||
|
struct z_object *obj = z_object_find(stack);
|
||||||
|
|
||||||
|
__ASSERT(obj != NULL, "stack object not found");
|
||||||
|
__ASSERT(obj->type == K_OBJ_THREAD_STACK_ELEMENT,
|
||||||
|
"bad stack object");
|
||||||
|
|
||||||
|
return obj->data.stack_data->priv;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_GEN_PRIV_STACKS */
|
||||||
|
|
||||||
#ifdef CONFIG_DYNAMIC_OBJECTS
|
#ifdef CONFIG_DYNAMIC_OBJECTS
|
||||||
struct dyn_obj {
|
struct dyn_obj {
|
||||||
struct z_object kobj;
|
struct z_object kobj;
|
||||||
|
|
|
@ -38,6 +38,7 @@ STACK_TYPE = "z_thread_stack_element"
|
||||||
thread_counter = 0
|
thread_counter = 0
|
||||||
sys_mutex_counter = 0
|
sys_mutex_counter = 0
|
||||||
futex_counter = 0
|
futex_counter = 0
|
||||||
|
stack_counter = 0
|
||||||
|
|
||||||
# Global type environment. Populated by pass 1.
|
# Global type environment. Populated by pass 1.
|
||||||
type_env = {}
|
type_env = {}
|
||||||
|
@ -57,6 +58,7 @@ class KobjectInstance:
|
||||||
global thread_counter
|
global thread_counter
|
||||||
global sys_mutex_counter
|
global sys_mutex_counter
|
||||||
global futex_counter
|
global futex_counter
|
||||||
|
global stack_counter
|
||||||
|
|
||||||
self.addr = addr
|
self.addr = addr
|
||||||
self.type_obj = type_obj
|
self.type_obj = type_obj
|
||||||
|
@ -76,6 +78,8 @@ class KobjectInstance:
|
||||||
elif self.type_obj.name == "k_futex":
|
elif self.type_obj.name == "k_futex":
|
||||||
self.data = "&futex_data[%d]" % futex_counter
|
self.data = "&futex_data[%d]" % futex_counter
|
||||||
futex_counter += 1
|
futex_counter += 1
|
||||||
|
elif self.type_obj.name == STACK_TYPE:
|
||||||
|
stack_counter += 1
|
||||||
else:
|
else:
|
||||||
self.data = 0
|
self.data = 0
|
||||||
|
|
||||||
|
@ -604,3 +608,8 @@ class ElfHelper:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_futex_counter():
|
def get_futex_counter():
|
||||||
return futex_counter
|
return futex_counter
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_stack_counter():
|
||||||
|
return stack_counter
|
||||||
|
|
||||||
|
|
|
@ -144,14 +144,10 @@ void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
|
||||||
#endif
|
#endif
|
||||||
"""
|
"""
|
||||||
|
|
||||||
metadata_names = {
|
|
||||||
"K_OBJ_THREAD" : "thread_id",
|
|
||||||
"K_OBJ_THREAD_STACK_ELEMENT" : "stack_size",
|
|
||||||
"K_OBJ_SYS_MUTEX" : "mutex",
|
|
||||||
"K_OBJ_FUTEX" : "futex_data"
|
|
||||||
}
|
|
||||||
|
|
||||||
def write_gperf_table(fp, eh, objs, static_begin, static_end):
|
def write_gperf_table(fp, eh, objs, static_begin, static_end):
|
||||||
|
syms = eh.get_symbols()
|
||||||
|
|
||||||
fp.write(header)
|
fp.write(header)
|
||||||
num_mutexes = eh.get_sys_mutex_counter()
|
num_mutexes = eh.get_sys_mutex_counter()
|
||||||
if num_mutexes != 0:
|
if num_mutexes != 0:
|
||||||
|
@ -171,9 +167,46 @@ def write_gperf_table(fp, eh, objs, static_begin, static_end):
|
||||||
fp.write(", ")
|
fp.write(", ")
|
||||||
fp.write("};\n")
|
fp.write("};\n")
|
||||||
|
|
||||||
|
metadata_names = {
|
||||||
|
"K_OBJ_THREAD" : "thread_id",
|
||||||
|
"K_OBJ_SYS_MUTEX" : "mutex",
|
||||||
|
"K_OBJ_FUTEX" : "futex_data"
|
||||||
|
}
|
||||||
|
|
||||||
|
if "CONFIG_GEN_PRIV_STACKS" in syms:
|
||||||
|
metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_data"
|
||||||
|
num_stack = eh.get_stack_counter()
|
||||||
|
if num_stack != 0:
|
||||||
|
fp.write("static u8_t Z_GENERIC_SECTION(.priv_stacks.noinit) "
|
||||||
|
" __aligned(Z_PRIVILEGE_STACK_ALIGN)"
|
||||||
|
" priv_stacks[%d][CONFIG_PRIVILEGED_STACK_SIZE];\n"
|
||||||
|
% num_stack);
|
||||||
|
|
||||||
|
fp.write("static struct z_stack_data stack_data[%d] = {\n"
|
||||||
|
% num_stack)
|
||||||
|
counter = 0
|
||||||
|
for _, ko in objs.items():
|
||||||
|
if ko.type_name != "K_OBJ_THREAD_STACK_ELEMENT":
|
||||||
|
continue
|
||||||
|
|
||||||
|
# ko.data currently has the stack size. fetch the value to
|
||||||
|
# populate the appropriate entry in stack_data, and put
|
||||||
|
# a reference to the entry in stack_data into the data value
|
||||||
|
# instead
|
||||||
|
size = ko.data
|
||||||
|
ko.data = "&stack_data[%d]" % counter
|
||||||
|
fp.write("\t{ %d, (u8_t *)(&priv_stacks[%d]) }"
|
||||||
|
% (size, counter))
|
||||||
|
if counter != (num_stack - 1):
|
||||||
|
fp.write(",")
|
||||||
|
fp.write("\n")
|
||||||
|
counter += 1
|
||||||
|
fp.write("};\n")
|
||||||
|
else:
|
||||||
|
metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_size"
|
||||||
|
|
||||||
fp.write("%%\n")
|
fp.write("%%\n")
|
||||||
# Setup variables for mapping thread indexes
|
# Setup variables for mapping thread indexes
|
||||||
syms = eh.get_symbols()
|
|
||||||
thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
|
thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
|
||||||
thread_idx_map = {}
|
thread_idx_map = {}
|
||||||
|
|
||||||
|
|
|
@ -1,140 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright (c) 2017 Linaro Limited
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
"""
|
|
||||||
Script to generate gperf tables mapping threads to their privileged mode stacks
|
|
||||||
|
|
||||||
Some MPU devices require that memory region definitions be aligned to their
|
|
||||||
own size, which must be a power of two. This introduces difficulties in
|
|
||||||
reserving memory for the thread's supervisor mode stack inline with the
|
|
||||||
K_THREAD_STACK_DEFINE() macro.
|
|
||||||
|
|
||||||
Instead, the stack used when a user thread elevates privileges is allocated
|
|
||||||
elsewhere in memory, and a gperf table is created to be able to quickly
|
|
||||||
determine where the supervisor mode stack is in memory. This is accomplished
|
|
||||||
by scanning the DWARF debug information in zephyr_prebuilt.elf, identifying
|
|
||||||
instances of 'struct k_thread', and emitting a gperf configuration file which
|
|
||||||
allocates memory for each thread's privileged stack and creates the table
|
|
||||||
mapping thread addresses to these stacks.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import argparse
|
|
||||||
import struct
|
|
||||||
from elf_helper import ElfHelper
|
|
||||||
|
|
||||||
kobjects = {
|
|
||||||
"z_thread_stack_element": (None, False)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
header = """%compare-lengths
|
|
||||||
%define lookup-function-name z_priv_stack_map_lookup
|
|
||||||
%language=ANSI-C
|
|
||||||
%global-table
|
|
||||||
%struct-type
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# Each privilege stack buffer needs to respect the alignment
|
|
||||||
# constraints as specified in arm/arch.h.
|
|
||||||
priv_stack_decl_temp = ("static u8_t __used"
|
|
||||||
" __aligned(Z_PRIVILEGE_STACK_ALIGN)"
|
|
||||||
" priv_stack_%x[CONFIG_PRIVILEGED_STACK_SIZE];\n")
|
|
||||||
|
|
||||||
|
|
||||||
includes = """#include <kernel.h>
|
|
||||||
#include <string.h>
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
structure = """struct _k_priv_stack_map {
|
|
||||||
char *name;
|
|
||||||
u8_t *priv_stack_addr;
|
|
||||||
};
|
|
||||||
%%
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# Different versions of gperf have different prototypes for the lookup
|
|
||||||
# function, best to implement the wrapper here. The pointer value itself is
|
|
||||||
# turned into a string, we told gperf to expect binary strings that are not
|
|
||||||
# NULL-terminated.
|
|
||||||
footer = """%%
|
|
||||||
u8_t *z_priv_stack_find(void *obj)
|
|
||||||
{
|
|
||||||
const struct _k_priv_stack_map *map =
|
|
||||||
z_priv_stack_map_lookup((const char *)obj, sizeof(void *));
|
|
||||||
return map->priv_stack_addr;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def write_gperf_table(fp, eh, objs):
|
|
||||||
fp.write(header)
|
|
||||||
|
|
||||||
# priv stack declarations
|
|
||||||
fp.write("%{\n")
|
|
||||||
fp.write(includes)
|
|
||||||
for obj_addr in objs:
|
|
||||||
fp.write(priv_stack_decl_temp % (obj_addr))
|
|
||||||
fp.write("%}\n")
|
|
||||||
|
|
||||||
# structure declaration
|
|
||||||
fp.write(structure)
|
|
||||||
|
|
||||||
for obj_addr in objs:
|
|
||||||
byte_str = struct.pack("<I" if eh.little_endian else ">I", obj_addr)
|
|
||||||
fp.write("\"")
|
|
||||||
for byte in byte_str:
|
|
||||||
val = "\\x%02x" % byte
|
|
||||||
fp.write(val)
|
|
||||||
|
|
||||||
fp.write("\",priv_stack_%x\n" % obj_addr)
|
|
||||||
|
|
||||||
fp.write(footer)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
|
||||||
global args
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description=__doc__,
|
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
||||||
|
|
||||||
parser.add_argument("-k", "--kernel", required=True,
|
|
||||||
help="Input zephyr ELF binary")
|
|
||||||
parser.add_argument(
|
|
||||||
"-o", "--output", required=True,
|
|
||||||
help="Output list of kernel object addresses for gperf use")
|
|
||||||
parser.add_argument("-v", "--verbose", action="store_true",
|
|
||||||
help="Print extra debugging information")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parse_args()
|
|
||||||
|
|
||||||
eh = ElfHelper(args.kernel, args.verbose, kobjects, [])
|
|
||||||
syms = eh.get_symbols()
|
|
||||||
max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
|
|
||||||
objs = eh.find_kobjects(syms)
|
|
||||||
if not objs:
|
|
||||||
sys.stderr.write("WARNING: zero kobject found in %s\n"
|
|
||||||
% args.kernel)
|
|
||||||
|
|
||||||
thread_counter = eh.get_thread_counter()
|
|
||||||
if thread_counter > max_threads:
|
|
||||||
sys.exit("Too many thread objects ({})\n"
|
|
||||||
"Increase CONFIG_MAX_THREAD_BYTES to {}"
|
|
||||||
.format(thread_counter, -(-thread_counter // 8)))
|
|
||||||
|
|
||||||
with open(args.output, "w") as fp:
|
|
||||||
write_gperf_table(fp, eh, objs)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
Loading…
Add table
Add a link
Reference in a new issue